home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / batchut / stnvjw23.zip / SETENV.ASM < prev    next >
Assembly Source File  |  1993-09-09  |  69KB  |  3,284 lines

  1. title Set Environment Variable Program.
  2. page 60,120            ; page length = 60
  3.                 ; page width  = 120
  4. ;
  5. ;    This program places a variable in the environment.
  6. ;
  7. ;    SETENV : Copyright (c) 1988 to 1993 by John Wolchak.  
  8. ;      I give permission to alter the code, but not to copy 
  9. ;      or redistribute the altered code without my explicit 
  10. ;      permission.  If you alter the code, please document 
  11. ;      changes and send me a copy, so all can have it.  The 
  12. ;      file Setenv.Doc must always accompany the SETENV 
  13. ;      program when a copy is made for another machine.  
  14. ;      This code, to the best of my knowledge works well.  
  15. ;      I disclaim any responsibility for the codes actions 
  16. ;      (use at your own risk).  
  17. ;
  18. ;    John Wolchak.
  19. ;    56 Physics Building
  20. ;    University of Saskatchewan.
  21. ;    Saskatoon, Saskatchewan
  22. ;    Canada     S7K 0W0
  23. ;    Phone: (306) 966-4852
  24. ;    Inter_Network: Wolchak@Admin.Usask.Ca
  25. ;
  26. ;    To assemble:
  27. ;    masm setenv,,,
  28. ;    link setenv,,,
  29. ;    exe2bin setenv.exe setenv.com
  30. ;    delete setenv.obj
  31. ;    delete setenv.exe
  32. ;
  33. code segment
  34. assume cs:code,ds:code
  35. org 100h
  36.  
  37. start:        jmp beginning
  38. ;
  39. ;        Data Area
  40. ;
  41. exit_code    db    03h        ; Environment variable created.
  42.                     ; PSP is Program Segment Prefix.
  43. cpsp        dw    00h        ; The psp of command.com.
  44. env_off        dw    00h        ; Environment offset address.
  45. env_siz        dw    00h        ; Environment size in bytes.
  46. dos_maj        db    00h        ; DOS major version.
  47. dos_min        db    00h        ; DOS minor version.
  48. set        db    "set "
  49. s_rce        dw    03h        ; Size of Root Comm Env.
  50. l_rce        db    "rce"
  51. u_rce        db    "RCE"
  52. v_rce        dw    00h        ; RCE value.
  53. a_rce        dw    00h        ; Segment address.
  54. ;d_rce        db    0ffh dup(0)    ; Data string of Set command.
  55. s_data        dw    00h        ; Size of environment data.
  56. a_env_var    dw    00h        ; Address of environment variable.
  57. s_env_var    dw    00h        ; Environment variable size.
  58. ;d_env_var    db    0ffh dup(0)    ; Environment data.
  59. ;null        db    00h,00h        ; Environment tail.
  60. y_prompt    dw    08h        ; Size of '%prompt '.
  61. x_prompt    dw    06h        ; Size.
  62. l_prompt    db    "prompt"
  63. u_prompt    db    "PROMPT"
  64. o_prompt    dw    00h        ; Offset of prompt.
  65. s_def        dw    03h        ; Size of default.
  66. l_def        db    "def"
  67. u_def        db    "DEF"
  68. x_def        dw    00h        ; Default value size.
  69. ;v_def        dw    100 dup(0)    ; Default value.
  70. s_echo        dw    06h        ; Size of echo.
  71. l_echo        db    "noecho"
  72. u_echo        db    "NOECHO"
  73. v_echo        dw    00h        ; Echo on.
  74. s_upper        dw    05h        ; Size of upper.
  75. l_upper        db    "upper"
  76. u_upper        db    "UPPER"
  77. v_upper        dw    00h        ; Upper case on.
  78. s_lower        dw    05h        ; Size of lower.
  79. l_lower        db    "lower"
  80. u_lower        db    "LOWER"
  81. v_lower        dw    00h        ; Lower case on.
  82. s_trim        dw    04h        ; Size of trim.
  83. l_trim        db    "trim"
  84. u_trim        db    "TRIM"
  85. v_trim        dw    00h        ; Trim leading spaces.
  86. w_trim        dw    00h        ; Trim trailing spaces.
  87. o_tmp        dw    00h        ; Save temporary address.
  88. s_timo        dw    05h        ; Size of timo.
  89. l_timo        db    "timo="
  90. u_timo        db    "TIMO="
  91. v_timo        dw    00h        ; Time out infinit.
  92. s_readkey    dw    07h        ; Size of readkey.
  93. l_readkey    db    "readkey"
  94. u_readkey    db    "READKEY"
  95. v_readkey    dw    00h        ; Readkey leading spaces.
  96. c_brk        db    00h        ; Control break status.
  97. d_ent        db    00h        ; Entry days.
  98. h_ent        db    00h        ; Entry hours.
  99. m_ent        db    00h        ; Entry minutes.
  100. s_ent        db    00h        ; Entry seconds.
  101. d_stt        db    00h        ; Stop time day.
  102. h_stt        db    00h        ; Stop time hours.
  103. m_stt        db    00h        ; Stop time minutes.
  104. s_stt        db    00h        ; Stop time seconds.
  105. f_stt        db    00h        ; Stop flag exit type.
  106. s_rep        dw    03h        ; Size of replace.
  107. l_rep        db    "rep"
  108. u_rep        db    "REP"
  109. v_rep        dw    00h
  110. s_arg1        dw    00h        ; Replace old value size.
  111. ;d_arg1        dw    100 dup(0)    ; Replace old value.
  112. s_arg2        dw    00h        ; Replace new value size.
  113. ;d_arg2        dw    100 dup(0)    ; Replace new value.
  114. s_chr        dw    03h        ; Size of chr.
  115. l_chr        db    "chr"
  116. u_chr        db    "CHR"
  117. n_chr        dw    00h        ; Decimal value character.
  118. s_elem        dw    04h        ; Size of element.
  119. l_elem        db    "elem"
  120. u_elem        db    "ELEM"
  121. c_elem        db    00h        ; Element delimiter
  122. e_elem        dw    00h        ; Element number.
  123. s_mid        dw    03h        ; Size of mid.
  124. l_mid        db    "mid"
  125. u_mid        db    "MID"
  126. y_mid        dw    00h        ; Substr starting position.
  127. z_mid        dw    00h        ; Substr length.
  128. b_env        dw    00h        ; Program env address.
  129. o_env        dw    00h        ; Variable offset.
  130. f_env        db    00h        ; Variable search.
  131. s_env        dw    00h        ; Variable name size.
  132. n_env        dw    20 dup(0)    ; Variable name.
  133. w_mid        dw    00h        ; Variable name size.
  134. x_mid        dw    20 dup(0)    ; Variable name.
  135. s_loc        dw    03h        ; Size of loc.
  136. l_loc        db    "loc"
  137. u_loc        db    "LOC"
  138. e_loc        dw    00h        ; Locate starting position.
  139. s_len        dw    03h        ; Size of len.
  140. l_len        db    "len"
  141. u_len        db    "LEN"
  142. s_sum        dw    03h        ; Size of sum.
  143. l_sum        db    "sum"
  144. u_sum        db    "SUM"
  145. v_sum        dw    00h
  146. f_sum        db    "+"        ; Add or subtract flag.
  147. nmb_sgn        db    "+"        ; Sign for number.
  148. nmb_tst        db    00h        ; Test for sign.
  149. dec_zfl        db    00h        ; Decimal zero flag.
  150. l_eq        dw    "eq"
  151. u_eq        dw    "EQ"
  152. l_lt        dw    "lt"
  153. u_lt        dw    "LT"
  154. l_le        dw    "le"
  155. u_le        dw    "LE"
  156. l_gt        dw    "gt"
  157. u_gt        dw    "GT"
  158. l_ge        dw    "ge"
  159. u_ge        dw    "GE"
  160. e_oper        db    00h        ; Test for equal.
  161. l_oper        db    00h        ; Test for less than.
  162. g_oper        db    00h        ; Test for greater than
  163. s_chgup        dw    05h        ; Size of Change upper.
  164. l_chgup        db    "chgup"
  165. u_chgup        db    "CHGUP"
  166. v_chgup        dw    00h        ; Change upper flag.
  167. s_chglo        dw    05h        ; Size of Change lower.
  168. l_chglo        db    "chglo"
  169. u_chglo        db    "CHGLO"
  170. v_chglo        dw    00h        ; Change lower flag.
  171. s_dosv        dw    04h        ; Size of Dos Major.
  172. l_dosv        db    "dosv"
  173. u_dosv        db    "DOSV"
  174. s_dosm        dw    04h        ; Size of Dos Minor.
  175. l_dosm        db    "dosm"
  176. u_dosm        db    "DOSM"
  177. s_cwd        dw    03h        ; Size of Current directory.
  178. l_cwd        db    "cwd"
  179. u_cwd        db    "CWD"
  180. ;d_cwd        db    0ffh dup(0)    ; Data area (temporary).
  181. s_cfd        dw    03h        ; Size of Current directory.
  182. l_cfd        db    "cfd"
  183. u_cfd        db    "CFD"
  184. s_time        dw    04h        ; Current time.
  185. l_time        db    "time"
  186. u_time        db    "TIME"
  187. s_date        dw    04h        ; Current date.
  188. l_date        db    "date"
  189. u_date        db    "DATE"
  190. z_date        db    "1"        ; Date format.
  191. s_drive        dw    05h        ; Size of drive.
  192. l_drive        db    "drive"
  193. u_drive        db    "DRIVE"
  194. s_path        dw    05h        ; Size of Path.
  195. d_path        db    "PATH="
  196. s_comspec    dw    08h        ; Size of Comspec=.
  197. d_comspec    db    "COMSPEC="
  198. s_prompt    dw    07h        ; Size of Prompt=.
  199. d_prompt    db    "PROMPT="
  200. s_setenv    dw    07h        ; Size of Setenv=.
  201. d_setenv    db    "SETENV="
  202. s_config    dw    07h        ; Size of Config=.
  203. d_config    db    "CONFIG="
  204. author        db    "Set Environment Variable Program V2.3 (c) 09-Sep-1993 "
  205.         db    "by John Wolchak.",13,10
  206. d_cwd        db    "Usage is:  SETENV <variable> <value>  "
  207.         db    "or  SETENV %rce <variable> <value>",13,10,9
  208.         db    "<variable> by it's self to erase variable.",13,10,9
  209.         db    "<value> can be: '%rep<del><txt1><del><txt2><del>' "
  210.         db    "text replace.",13,10,9
  211.         db    "  '%chgup' or 'chglo' upper/lower case environment "
  212.         db    "variable data.",13,10,9
  213.         db    "  '%prompt %noecho %upper "
  214. d_rce        db    "%def<del><text><del> <message>'.",13,10,9
  215.         db    "     '%noecho' for no echo, '%upper' '%lower' "
  216.         db    "upper/lower case only.",13,10,9
  217.         db    "     '%def<del><text><del>' supply a default,"
  218.         db    " '%trim' trim spaces.",13,10,9
  219.         db    "     '%timo=hh:mm:ss' prompt time out, time length."
  220.         db    13,10,9
  221.         db    "<value> can include keys such as:   "
  222.         db    "ie  setenv drivedir %drive:%cwd",13,10,9
  223. d_arg1        db    "  %dosv / %dosm for DOS major / minor version."
  224.         db    13,10,9
  225.         db    "  %cwd or %cfd for current directory, "
  226.         db    "  %drive for drive letter.",13,10,9
  227.         db    "  %time / %daten for current time / date format 'n'."
  228.         db    13,10,9
  229. v_def        db    "  %+n / %-n for default drive plus / minus 'n'."
  230.         db    13,10,9
  231.         db    "  %loc/<n>/<var>/<str>/  %len/<var>/"
  232.         db    "  %sum/<var>/<n>/",13,10,9
  233.         db    "  %mid/<var>/<n1>/<n2>/  %elem/<n>/<char>/<var>/"
  234.         db    "  %chr/<n>/",13,10
  235. d_arg2        db    "Note:     Use %% to represent a single % in BAT files."
  236.         db    13,10
  237.         db    "       SETENV return codes:",9,9
  238.         db    "no command, help issued     00h",13,10
  239. d_env_var    db    "root environment set        01h",9
  240.         db    "environment variable erased    02h",13,10
  241.         db    "environment variable created    03h",9
  242.         db    "don't know about MS-DOS V1.x    04h",13,10
  243.         db    "environment variable updated    05h",9
  244.         db    "unmatched delimiter        06h",13,10
  245.         db    "not a valid argument        07h",9
  246.         db    "environment variable not found    08h",13,10
  247.         db    "offset drive will be invalid    09h",9
  248.         db    "environment space is full    10h"
  249.         db    "$"
  250. get4d_err    db    "Error - can't find SETENV at top of environment space.$"
  251. ;
  252. ;    If the help is changed then the variables d_cwd, d_rce
  253. ;        v_def, d_arg1, d_arg2, and d_env_var need to be
  254. ;        changed to  the size of the comments above.
  255. ;        v_def, d_arg1, and d_arg2 are approximately 100
  256. ;        d_cwd, d_rce, and d_env_var are approximately 255
  257. ;        remember the DOS command line is 123 and you can %rep///
  258. ;
  259. ;        Code Area
  260. ;
  261. Beginning:
  262.         mov sp, offset stack    ; Set up local stack.
  263.         mov si, 80h        ; Offset of command line.
  264.         lodsb            ; Get a byte.
  265.         cmp al, 00h        ; Is there any data.
  266.         jnz get_ver        ; Yes. Jump.
  267. dis_help:
  268.         mov dx, offset author    ; Help message.
  269.         mov ah, 09h        ; Display it.
  270.         int 21h
  271.         mov exit_code, 00h    ; No command, help issued.
  272.         jmp nor_term        ; Exit.
  273.  
  274. get_ver:    
  275.         mov ah, 30h        ; Get DOS version number.
  276.         int 21h
  277.  
  278.         mov dos_maj, al
  279.         mov dos_min, ah
  280.  
  281.         cmp ah, 01h
  282.         jnz cont
  283.         mov exit_code, 04h    ; No MS-DOS version 1.x.
  284.         jmp nor_term        ; Exit.
  285.  
  286. ;        Get rid of leading spaces and tabs.
  287. cont:
  288.         lodsb            ; Get a byte.
  289.         cmp al, " "        ; Is it a leading blank.
  290.         jz cont            ; Yes.  Loop.
  291.         cmp al, 09h        ; Is it a leading tab.
  292.         jz cont            ; Yes.  Loop.
  293.         cmp al, "%"        ; Is it a special one.
  294.         jz rce            ; Yes.  Use it.
  295.         cmp al, 0dh        ; Is it a carriage return.
  296.         jz dis_help        ; Yes. dis_help.
  297. cont_on:
  298.         dec si
  299.         jmp var
  300.  
  301. rce:
  302. ;        Handle %rce.
  303.         push si
  304.         mov di, si        ; Set destination.
  305.         mov si, offset l_rce    ; Set source.
  306.         mov cx, s_rce
  307.         rep cmpsb        ; Is it %rce.
  308.         jz set_rce        ; Yes, Jump out.
  309.  
  310.         pop si
  311.         push si
  312.         mov di, si        ; Set destination.
  313.         mov si, offset u_rce    ; Set source.
  314.         mov cx, s_rce
  315.         rep cmpsb        ; Is it %RCE.
  316.         jz set_rce        ; Yes, Jump out.
  317.  
  318.         pop si
  319.         jmp cont_on
  320. set_rce:
  321.         pop si
  322.         inc si
  323.         inc si
  324.         inc si
  325.         mov v_rce, 01h        ; Root Command Environment.
  326.  
  327. ;        Get rid of leading spaces and tabs.
  328. var:
  329.         lodsb            ; Get a byte.
  330.         cmp al, " "        ; Is it a leading blank.
  331.         jz var            ; Yes.  Loop.
  332.         cmp al, 09h        ; Is it a leading tab.
  333.         jz var            ; Yes.  Loop.
  334.  
  335.         dec si            ; Backup for the character.
  336.         mov a_env_var, si    ; Offset of the variable.
  337.         mov di, offset d_env_var ; Offset of env. variable.
  338.  
  339. ;        Get the variable name,
  340. ;        and convert to upper case.
  341. get_var:
  342.         lodsb            ; Get a byte.
  343.         cmp al, " "        ; Is it the end of the variable?
  344.         jz var_end        ; Yes.  Jump out.
  345.         cmp al, 09h        ; Is it the end of the variable?
  346.         jz var_end        ; Yes.  Jump out.
  347.         cmp al, "="        ; Is it the end of the variable?
  348.         jz var_end        ; Yes. Jump out.
  349.         cmp al, 0dh        ; Is it the end.
  350.         jz no_data        ; Yes. We got it.
  351.         cmp al, "z"        ; Is
  352.         jg no_lower        ;   it
  353.         cmp al, "a"        ;     lower
  354.         jb no_lower        ;       case?
  355.         sub al, 20h        ; Make it upper case.
  356. no_lower:
  357.         stosb            ; Save the byte.
  358.         jmp get_var
  359.  
  360. no_data:
  361.         mov al, 0dh
  362.         mov [si], al
  363. var_end:
  364.         mov al, "="        ; Set the end of variable.
  365.         stosb            ; Save it.
  366.         mov -1[si], al        ; And the command line.
  367.  
  368.         mov ax, si        ; Get the offset.
  369.         mov bx, a_env_var    ; Beginning of the variable.
  370.         sub ax, bx        ; Get the variable length.
  371.         mov s_env_var, ax    ; And save it.
  372.  
  373. var_end1:
  374.         lodsb            ; Get a byte.
  375.         cmp al, " "        ; Is it a blank.
  376.         jz var_end1        ; Loop.
  377.         cmp al, 09h        ; Is it a tab.
  378.         jz var_end1        ; Loop.
  379.         dec si
  380.  
  381.         mov al, [si]        ; Get a byte.
  382.         cmp al, "%"        ; Is it a special one.
  383.         jz prompt        ; Yes. Jump out.
  384.  
  385. ;        Get the data part.
  386. get_data:
  387.         mov al, [si]        ; Get a byte.
  388.         cmp al, "%"        ; Is it a special one.
  389.         jz percent_near        ; Yes. Jump out.
  390. get_next:
  391.         lodsb            ; Get a byte.
  392.         cmp al, 0dh        ; Is it the end.
  393.         jz data_end_near    ; Yes. We got it.
  394.         stosb            ; Save the byte.
  395.         jmp get_data
  396.  
  397. data_end_near:
  398.         jmp data_end
  399. percent_near:
  400.         jmp percent
  401.  
  402. ;        Handle %prompt.
  403. prompt:
  404.         mov o_prompt, si
  405.         inc si
  406.         push di
  407.         push si
  408.  
  409.         mov di, si        ; Set destination.
  410.         mov si, offset l_prompt    ; Set Source.
  411.         mov cx, x_prompt
  412.         rep cmpsb        ; Is it %prompt.
  413.         jz sub_fun_near        ; Yes.
  414.  
  415.         pop si
  416.         push si
  417.         mov di, si        ; Set destination.
  418.         mov si, offset u_prompt    ; Set source.
  419.         mov cx, x_prompt
  420.         rep cmpsb        ; Is it %PROMPT.
  421.         jz sub_fun_near        ; Yes.
  422.  
  423. ;        Then check for replace
  424.         jmp replace
  425.  
  426. sub_fun_near:
  427.         jmp sub_fun
  428.  
  429. get_prompt:
  430.         pop si
  431.         push si
  432.         dec si
  433.  
  434.         mov ax, si        ; Jump
  435.         mov cx, y_prompt    ;   the
  436.         add ax, cx        ;     %prompt
  437.         mov si, ax        ;       string.
  438.  
  439. ;        Display the prompt.
  440. prompt1:
  441.         lodsb            ; Scan for
  442.         cmp al, 0dh        ;   a return.
  443.         jz prompt2
  444.  
  445.         call make_char        ; Generate character.
  446.         mov dl, al        ; Output Character.
  447.         mov ah, 02h
  448.         int 21h
  449.         jmp prompt1
  450. prompt2:
  451.         pop si
  452.         push si
  453.         mov di, si
  454.         mov bx, di
  455.  
  456. ;        Check do we time out.
  457.         cmp v_timo, 00h        ; Do we timeout?
  458.         jnz check0        ; Yes. Jumpout.
  459.         jmp prompt3
  460.  
  461. check0:
  462. ;        Get the current time, and set the stop time.
  463.         mov ah, 2ch        ; Get the
  464.         int 21h            ;   current time.
  465.         mov dl, d_ent        ; No day.
  466.  
  467.         add dh, s_ent        ; Add the seconds
  468.         cmp dh, 3ch
  469.         jb get0
  470.         sub dh, 3ch        ; and correct.
  471.         inc cl
  472. get0:
  473.         add cl, m_ent        ; Add the minutes
  474.         cmp cl, 3ch
  475.         jb get1
  476.         sub cl, 3ch        ; and correct.
  477.         inc ch
  478. get1:
  479.         add ch, h_ent        ; Add the hours
  480.         cmp ch, 18h
  481.         jb get2
  482.         sub ch, 18h        ; and correct.
  483.         inc dl            ; New day.
  484. get2:
  485.         mov s_stt, dh        ; Save
  486.         mov m_stt, cl        ;   the
  487.         mov h_stt, ch        ;     stop
  488.         mov d_stt, dl        ;       time.
  489. ;        end of get and set time.
  490.  
  491. ;        Get and check time.
  492.         mov al, 00h        ; Set for
  493.         mov f_stt, al        ;   read input.
  494.  
  495.         mov ah, 33h        ; Check Ctrl-Break.
  496.         mov al, 00h
  497.         int 21
  498.         mov c_brk, dl        ; Save current setting.
  499.         mov ah, 33h        ; Set Ctrl-Break.
  500.         mov al, 01h
  501.         mov dl, 01h
  502.         int 21
  503. check1:
  504.         mov ah, 0bh        ; Check
  505.         int 21h            ;   input
  506.         cmp al, 00h        ;     waiting.
  507.         jnz check9        ; Yes. Jump out.
  508.  
  509.         mov ah, 2ch        ; Get the
  510.         int 21h            ;   current time.
  511.  
  512.         cmp d_stt, 00h        ; Over a midnight?
  513.         jz check3
  514.         cmp ch, 00h        ; New hour?
  515.         jnz check1
  516.         cmp cl, 00h        ; New minute?
  517.         jnz check1
  518.         cmp dh, 00h        ; New second?
  519.         jnz check1
  520.         cmp dl, 00h        ; New hundredth second?
  521.         jz check1
  522.         mov al, d_stt        ; Decrement
  523.         dec al            ;   a day
  524.         mov d_stt, al        ;     and save.
  525. check2:
  526.         mov ah, 2ch        ; Get the
  527.         int 21h            ;   current time.
  528.  
  529.         cmp dh, 00h        ; Loop until
  530.         jz check2        ;   the second changes.
  531.  
  532.         jmp check1
  533.  
  534. check3:
  535.         cmp ch, h_stt        ; Correct hour?
  536.         jb check1        ; No. Loop.
  537.         cmp cl, m_stt        ; Correct minute?
  538.         jb check1        ; No. Loop.
  539.         cmp dh, s_stt        ; Correct second?
  540.         jb check1        ; No. Loop.
  541.         mov al, 01h        ; Set for
  542.         mov f_stt, al        ;   timeout.
  543.  
  544. check9:
  545.         mov ah, 33h        ; Restore Ctrl-Break.
  546.         mov al, 01h
  547.         mov dl, c_brk
  548.         int 21
  549.  
  550.         cmp f_stt, 00h        ; Is someone typing?
  551.         jz prompt3        ; Yes. Jump out.
  552.         mov al, 0dh        ; Fake carriage return read
  553.         jmp prompt7
  554.  
  555. ;        end of check time.
  556.  
  557. prompt3:
  558. ;        Read the response.
  559.         mov ah, 08h        ; Read keyboard.
  560.         int 21h
  561.  
  562.         cmp v_upper, 01h    ; Upper case on.
  563.         jnz not_upper
  564.         call uppercase        ; Convert to uppercase.
  565. not_upper:
  566.  
  567.         cmp v_lower, 01h    ; Lower case on.
  568.         jnz not_lower
  569.         call lowercase        ; Convert to lowercase.
  570. not_lower:
  571.  
  572.         cmp v_readkey, 01h    ; Readkey on.
  573.         jnz not_readkey        ; No.  Jump readkey part.
  574.  
  575.         cmp v_echo, 00h        ; Do we echo the character.
  576.         jnz noecho_readkey
  577.  
  578.         mov dl, al        ; Output Character.
  579.         mov ah, 02h
  580.         int 21h
  581.  
  582. noecho_readkey:
  583.         stosb            ; Save the byte.
  584.         mov al, 0dh        ; Put in a carriage return.
  585.  
  586. not_readkey:
  587.         cmp al, 08h        ; Got a backspace character.
  588.         jz prompt4
  589.         cmp al, 7fh        ; Got a delete character.
  590.         jnz prompt6
  591.  
  592. prompt4:
  593.         mov dx, di        ; Current pointer.
  594.         cmp bx, dx        ; Have we moved?
  595.         jz prompt3        ; No. Jump.
  596.  
  597.         cmp v_echo, 00h        ; Do we echo the character.
  598.         jnz prompt5
  599.  
  600.         mov dl, 08h        ; Print a backspace.
  601.         mov ah, 02h
  602.         int 21h
  603.  
  604.         mov dl, " "        ; Print a space.
  605.         mov ah, 02h
  606.         int 21h
  607.  
  608.         mov dl, 08h        ; Print a backspace.
  609.         mov ah, 02h
  610.         int 21h
  611.  
  612. prompt5:
  613.         dec di
  614.         jmp prompt3        ; Backup on the last byte.
  615.  
  616. prompt6:
  617.         cmp v_echo, 00h        ; Do we echo the character.
  618.         jnz prompt7
  619.  
  620.         mov dl, al        ; Output Character.
  621.         mov ah, 02h
  622.         int 21h
  623.  
  624. prompt7:
  625.         cmp al, " "        ; Is it a space.
  626.         jnz not_space
  627.  
  628.         cmp v_trim, 01h        ; Trim leading space.
  629.         jz prompt3
  630.  
  631. not_space:
  632.         mov v_trim, 00h        ; No Trim.
  633.  
  634.         stosb            ; Save the byte.
  635.         cmp al, 0dh        ; Got a return.
  636.         jnz prompt3
  637.  
  638.         mov dl, 0dh        ; Print a return.
  639.         mov ah, 02h
  640.         int 21h
  641.         mov dl, 0ah        ; Print a linefeed.
  642.         mov ah, 02h
  643.         int 21h
  644.  
  645.         cmp w_trim, 01h        ; Trim trailing space.
  646.         jnz trim_nosp
  647.         dec di
  648.  
  649. trim_sp:
  650.         dec di
  651.         mov al, [di]        ; Get a byte.
  652.  
  653.         cmp al, " "        ; Is is a space.
  654.         jz trim_sp        ; Yes. Loop.
  655.  
  656.         inc di
  657.         mov al, 0dh        ; Put in a carriage return.
  658.         stosb
  659.  
  660. trim_nosp:
  661.         pop si
  662.         push si
  663.         mov al, [si]
  664.         cmp al ,0dh        ; Is it a return.
  665.         jnz prompt9        ; No.  Jump out.
  666.  
  667.         mov di, si        ; Move
  668.         mov si, offset v_def    ;   the default
  669.         mov cx, x_def        ;     in place.
  670.         rep movsb
  671.  
  672.         mov al, 0dh
  673.         stosb
  674. prompt9:
  675.         pop si
  676.         pop di
  677.  
  678.         cmp v_readkey, 01h    ; Readkey on.
  679.         jz cont_readkey        ; Yes finish up readkey.
  680.         jmp get_data
  681.  
  682. cont_readkey:
  683.         lodsb            ; Get a byte.
  684.         stosb            ; Save the byte.
  685.         jmp data_end
  686.  
  687. ;        white space in front of function
  688. sub_fun:
  689.         mov si, di
  690. sub_fun0:
  691.         lodsb
  692.         mov o_tmp, si
  693.         cmp al, " "        ; Is it space?
  694.         jz sub_fun0        ; Yes. Ignore.
  695.         cmp al, 09h        ; Is it a tab?
  696.         jz sub_fun0        ; Yes. Ignore.
  697.         cmp al, "%"        ; Is it a special one.
  698.         jz echo         ; Yes.  Use it.
  699. sub_fun1:
  700.         dec si
  701.         mov ax, si        ; Get current pointer.
  702.         mov bx, o_prompt    ; Get prompt value start.
  703.         sub ax, bx        ; To get prompt noise length.
  704.         mov y_prompt, ax    ; Save it.
  705.  
  706.         jmp get_prompt
  707.  
  708.  
  709. ;        Handle %noecho.
  710. echo:
  711.         mov si, o_tmp        ; Set destination.
  712.         mov di, offset l_echo    ; Set Source.
  713.         mov cx, s_echo
  714.         rep cmpsb        ; Is it %noecho.
  715.         jz get_echo        ; Yes.
  716.  
  717.         mov si, o_tmp        ; Set destination.
  718.         mov di, offset u_echo    ; Set source.
  719.         mov cx, s_echo
  720.         rep cmpsb        ; Is it %NOECHO.
  721.         jz get_echo        ; Yes.
  722.  
  723.         jmp upper
  724.  
  725. get_echo:
  726.         mov v_echo, 01h        ; Set no echo.
  727.         jmp sub_fun0
  728.  
  729. ;        Handle %upper.
  730. upper:
  731.         mov si, o_tmp        ; Set destination.
  732.         mov di, offset l_upper    ; Set Source.
  733.         mov cx, s_upper
  734.         rep cmpsb        ; Is it %upper.
  735.         jz get_upper        ; Yes.
  736.  
  737.         mov si, o_tmp        ; Set destination.
  738.         mov di, offset u_upper    ; Set source.
  739.         mov cx, s_upper
  740.         rep cmpsb        ; Is it %UPPER.
  741.         jz get_upper        ; Yes.
  742.  
  743.         jmp lower
  744.  
  745. get_upper:
  746.         mov v_upper, 01h    ; Set upper case.
  747.         jmp sub_fun0
  748.  
  749. ;        Handle %lower.
  750. lower:
  751.         mov si, o_tmp        ; Set destination.
  752.         mov di, offset l_lower    ; Set Source.
  753.         mov cx, s_lower
  754.         rep cmpsb        ; Is it %lower.
  755.         jz get_lower        ; Yes.
  756.  
  757.         mov si, o_tmp        ; Set destination.
  758.         mov di, offset u_lower    ; Set source.
  759.         mov cx, s_lower
  760.         rep cmpsb        ; Is it %LOWER.
  761.         jz get_lower        ; Yes.
  762.  
  763.         jmp trim
  764.  
  765. get_lower:
  766.         mov v_lower, 01h    ; Set lower case.
  767.         jmp sub_fun0
  768.  
  769. ;        Handle %trim.
  770. trim:
  771.         mov si, o_tmp        ; Set destination.
  772.         mov di, offset l_trim    ; Set Source.
  773.         mov cx, s_trim
  774.         rep cmpsb        ; Is it %trim.
  775.         jz get_trim        ; Yes.
  776.  
  777.         mov si, o_tmp        ; Set destination.
  778.         mov di, offset u_trim    ; Set source.
  779.         mov cx, s_trim
  780.         rep cmpsb        ; Is it %TRIM.
  781.         jz get_trim        ; Yes.
  782.  
  783.         jmp readkey
  784.  
  785. get_trim:
  786.         mov v_trim, 01h        ; Trim leading spaces.
  787.         mov w_trim, 01h        ; Trim trailing spaces.
  788.         jmp sub_fun0
  789.  
  790.  
  791. ;        Handle %readkey.
  792. readkey:
  793.         mov si, o_tmp        ; Set destination.
  794.         mov di, offset l_readkey ; Set Source.
  795.         mov cx, s_readkey
  796.         rep cmpsb        ; Is it %readkey.
  797.         jz get_readkey        ; Yes.
  798.  
  799.         mov si, o_tmp        ; Set destination.
  800.         mov di, offset u_readkey ; Set source.
  801.         mov cx, s_readkey
  802.         rep cmpsb        ; Is it %READKEY.
  803.         jz get_readkey        ; Yes.
  804.  
  805.         jmp timo
  806.  
  807. get_readkey:
  808.         mov v_readkey, 01h    ; Set readkey.
  809.         jmp sub_fun0
  810.  
  811. ;        Handle %timo.
  812. timo:
  813.         mov si, o_tmp        ; Set destination.
  814.         mov di, offset l_timo    ; Set Source.
  815.         mov cx, s_timo
  816.         rep cmpsb        ; Is it %timo.
  817.         jz get_timo        ; Yes.
  818.  
  819.         mov si, o_tmp        ; Set destination.
  820.         mov di, offset u_timo    ; Set source.
  821.         mov cx, s_timo
  822.         rep cmpsb        ; Is it %TIMO.
  823.         jz get_timo        ; Yes.
  824.  
  825.         jmp default
  826.  
  827. get_timo:
  828. ;        mov si, di
  829. timo1:
  830.         lodsb
  831.         cmp al, ":"        ; Time
  832.         jz timo2        ;   dividers
  833.         cmp al, "."        ;     semi-colon
  834.         jz timo2        ;       and period.
  835.         cmp al, "-"
  836.         jz timo2
  837.  
  838.         cmp al, "0"        ; Is
  839.         jb timo3        ;   it
  840.         cmp al, "9"        ;     a 
  841.         jg timo3        ;       digit?
  842.  
  843.         sub al, 30h        ; Make it binary.
  844.         mov bh, al        ; Temp. save it.
  845.         mov al, s_ent        ; Get the seconds.
  846.         mov bl, 0ah        ; Multiply 
  847.         mul bl            ;   by ten.
  848.         add al, bh        ; Add next digit.
  849.         mov s_ent, al        ; Save the seconds.
  850.         jmp timo1
  851.  
  852. timo2:
  853.         mov al, h_ent
  854.         mov d_ent, al
  855.         mov al, m_ent        ; Roll
  856.         mov h_ent, al        ;   over
  857.         mov al, s_ent        ;     the time
  858.         mov m_ent, al        ;       components.
  859.         mov al, 00h
  860.         mov s_ent, al
  861.         jmp timo1
  862.  
  863. timo3:
  864.         mov v_timo, 01h        ; Set time out.
  865.         dec si
  866.         jmp sub_fun0
  867.  
  868. ;        Handle %def.
  869. default:
  870.         mov si, o_tmp        ; Set destination.
  871.         mov di, offset l_def    ; Set Source.
  872.         mov cx, s_def
  873.         rep cmpsb        ; Is it %def.
  874.         jz get_default        ; Yes.
  875.  
  876.         mov si, o_tmp        ; Set destination.
  877.         mov di, offset u_def    ; Set source.
  878.         mov cx, s_def
  879.         rep cmpsb        ; Is it %DEF.
  880.         jz get_default        ; Yes.
  881.  
  882.         mov si, o_tmp
  883.         jmp sub_fun1
  884.  
  885. get_default:
  886.         lodsb            ; Get the delimiter.
  887.         mov dl, al        ; Save it.
  888.         mov di, offset v_def    ; Get address for save of value.
  889.         mov x_def, si        ; Save the start of the value.
  890. default1:
  891.         lodsb            ; Get a byte.
  892.         cmp al, 0dh        ; Is it a return?
  893.         jz default2        ; Yes. Jump out.
  894.  
  895.         cmp al, dl        ; Is it the delimiter?
  896.         jz default3        ; Yes. Jump out.
  897.         stosb            ; Save it.
  898.         jmp default1
  899. default2:
  900.         mov -1[si], dl        ; No
  901.         mov ah, " "        ;   delimiter
  902.         mov [si], ah        ;     so
  903.         mov ah, ">"        ;       create
  904.         mov 1[si], ah        ;         the
  905.         mov 2[si], al        ;           info.
  906.         dec si
  907.         mov cs:[exit_code], 06h    ; Unmatched delimter.
  908.         jmp default1
  909.  
  910. default3:
  911.         mov ax, si        ; Get current pointer.
  912.         mov bx, x_def        ; Get default value start.
  913.         sub ax, bx        ; To get length of default value.
  914.         dec ax
  915.         mov x_def, ax        ; Save it.
  916.  
  917.         jmp sub_fun0
  918.  
  919. ;        Handle %rep.
  920. replace:
  921.         pop si
  922.         push si
  923.         mov di, si        ; Set destination.
  924.         mov si, offset l_rep    ; Set Source.
  925.         mov cx, s_rep
  926.         rep cmpsb        ; Is it %rep.
  927.         jz get_replace        ; Yes.
  928.  
  929.         pop si
  930.         push si
  931.         mov di, si        ; Set destination.
  932.         mov si, offset u_rep    ; Set Source.
  933.         mov cx, s_rep
  934.         rep cmpsb        ; Is it %REP.
  935.         jz get_replace        ; Yes.
  936.  
  937.         jmp chgup        ; No. Jump out.
  938.  
  939. get_replace:
  940.         mov si, di
  941.         lodsb            ; Get the delimiter.
  942.         mov dl, al        ; Save it.
  943.         mov di, offset d_arg1    ; Get address for save of value.
  944.         mov cx, 00h
  945. replace1:
  946.         lodsb            ; Get a byte.
  947.         cmp al, 0dh        ; Is it a return?
  948.         jz replace2        ; Yes. Jump out.
  949.  
  950.         cmp al, dl        ; Is it the delimiter?
  951.         jz replace3        ; Yes. Jump out.
  952.         stosb            ; Save it.
  953.         inc cx            ; Increment the count
  954.         jmp replace1
  955. replace2:
  956.         dec si
  957.         mov cs:[exit_code], 06h    ; Unmatched delimter.
  958. ;        You could take out the next line.
  959.         jmp nor_term        ; Exit.
  960.  
  961. replace3:
  962.         mov s_arg1, cx        ; Save size.
  963.         mov di, offset d_arg2    ; Get address for save of value.
  964.         mov cx, 00h
  965. replace4:
  966.         lodsb            ; Get a byte.
  967.         cmp al, 0dh        ; Is it a return?
  968.         jz replace5        ; Yes. Jump out.
  969.  
  970.         cmp al, dl        ; Is it the delimiter?
  971.         jz replace6        ; Yes. Jump out.
  972.         stosb            ; Save it.
  973.         inc cx            ; Increment the count
  974.         jmp replace4
  975.  
  976. replace5:
  977.         dec si
  978.         mov cs:[exit_code], 06h    ; Unmatched delimter.
  979. replace6:
  980.         mov s_arg2, cx        ; Save size.
  981.         mov v_rep, 0ffh        ; Flag the replace.
  982.  
  983.         pop si
  984.         pop di
  985.         inc si
  986.         jmp data_end
  987.  
  988. ;        Handle %chgup.
  989. chgup:
  990.         pop si
  991.         push si
  992.         mov di, si        ; Set destination.
  993.         mov si, offset l_chgup    ; Set Source.
  994.         mov cx, s_chgup
  995.         rep cmpsb        ; Is it %chgup.
  996.         jz get_chgup        ; Yes.
  997.  
  998.         pop si
  999.         push si
  1000.         mov di, si        ; Set destination.
  1001.         mov si, offset u_chgup    ; Set Source.
  1002.         mov cx, s_chgup
  1003.         rep cmpsb        ; Is it %CHGUP.
  1004.         jz get_chgup        ; Yes.
  1005.  
  1006.         jmp chglo        ; No. Jump out.
  1007.  
  1008. get_chgup:
  1009.         mov v_chgup, 0ffh
  1010.         pop si
  1011.         pop di
  1012.         inc si
  1013.         jmp data_end
  1014.  
  1015. ;        Handle %chglo.
  1016. chglo:
  1017.         pop si
  1018.         push si
  1019.         mov di, si        ; Set destination.
  1020.         mov si, offset l_chglo    ; Set Source.
  1021.         mov cx, s_chglo
  1022.         rep cmpsb        ; Is it %chglo.
  1023.         jz get_chglo        ; Yes.
  1024.  
  1025.         pop si
  1026.         push si
  1027.         mov di, si        ; Set destination.
  1028.         mov si, offset u_chglo    ; Set Source.
  1029.         mov cx, s_chglo
  1030.         rep cmpsb        ; Is it %CHGLO.
  1031.         jz get_chglo        ; Yes.
  1032.  
  1033.         jmp logical        ; No. Jump out.
  1034.  
  1035. get_chglo:
  1036.         mov v_chglo, 0ffh
  1037.         pop si
  1038.         pop di
  1039.         inc si
  1040.         jmp data_end
  1041.  
  1042. ;        handle %{operator}
  1043. logical:
  1044.         pop si
  1045.         push si
  1046.         lodsb            ; Get a byte.
  1047.         mov ah, al        ; First byte.                
  1048.         lodsb            ; Second byte.
  1049.  
  1050.         mov dx, l_eq        ; Is
  1051.         cmp ax, dx        ;   it
  1052.         jz equal        ;     eq.
  1053.         mov dx, u_eq        ; Is
  1054.         cmp ax, dx        ;   it
  1055.         jz equal        ;     EQ.
  1056.  
  1057.         mov dx, l_lt        ; Is
  1058.         cmp ax, dx        ;   it
  1059.         jz less_than        ;     lt.
  1060.         mov dx, u_lt        ; Is
  1061.         cmp ax, dx        ;   it
  1062.         jz less_than        ;     LT.
  1063.  
  1064.         mov dx, l_le        ; Is
  1065.         cmp ax, dx        ;   it
  1066.         jz less_equal        ;     le.
  1067.         mov dx, u_le        ; Is
  1068.         cmp ax, dx        ;   it
  1069.         jz less_equal        ;     LE.
  1070.  
  1071.         mov dx, l_gt        ; Is
  1072.         cmp ax, dx        ;   it
  1073.         jz greater_than        ;     gt.
  1074.         mov dx, u_gt        ; Is
  1075.         cmp ax, dx        ;   it
  1076.         jz greater_than        ;     GT.
  1077.  
  1078.         mov dx, l_ge        ; Is
  1079.         cmp ax, dx        ;   it
  1080.         jz greater_equal    ;     ge.
  1081.         mov dx, u_ge        ; Is
  1082.         cmp ax, dx        ;   it
  1083.         jz greater_equal    ;     GE.
  1084.  
  1085.         pop si
  1086.         pop di
  1087.         dec si
  1088.         jmp get_data        ; No. Jump out.
  1089.  
  1090.  
  1091. equal:
  1092.         mov e_oper, 0ffh    ; Set for equal.
  1093.         jmp arg_one
  1094.  
  1095. less_equal:
  1096.         mov e_oper, 0ffh    ; Set for equal.
  1097. less_than:
  1098.         mov l_oper, 0ffh    ; Set for less than.
  1099.         jmp arg_one
  1100.  
  1101. greater_equal:
  1102.         mov e_oper, 0ffh    ; Set for equal.
  1103. greater_than:
  1104.         mov g_oper, 0ffh    ; Set for greater than.
  1105.         jmp arg_one
  1106.  
  1107. ;        Get argument one.
  1108. arg_one:
  1109.         lodsb            ; Get a byte.
  1110.         cmp al, " "        ; Is it a space.
  1111.         jz test_arg1
  1112.         cmp al, 09h        ; Is it a tab.
  1113.         jz test_arg1
  1114.         cmp al, "'"        ; Is it a quote.
  1115.         jz quote1
  1116.         cmp al, '"'        ; Is it a quote.
  1117.         jz quote1
  1118.  
  1119.         jmp log_exit
  1120.  
  1121. quote1:
  1122.         mov di, offset d_arg1    ; Address of argument one.
  1123.         call get_quote        ; Get the quoted string.
  1124.  
  1125.         cmp exit_code, 06h    ; Unmatched quote?
  1126.         jz test_end
  1127.  
  1128.         mov s_arg1, cx        ; Save the size.
  1129.         jmp arg_two
  1130.  
  1131. test_arg1:
  1132.         lodsb            ; Get a byte.
  1133.         cmp al, " "        ; Is it a space.
  1134.         jz test_arg1
  1135.         cmp al, 09h        ; Is it a tab.
  1136.         jz test_arg1
  1137.         cmp al, "'"        ; Is it a quote.
  1138.         jz quote1
  1139.         cmp al, '"'        ; Is it a quote.
  1140.         jz quote1
  1141.         cmp al, 0dh        ; Is it a carriage return.
  1142.         jz no_argum
  1143.  
  1144.         dec si
  1145.         call get_var0        ; Get the variable.
  1146.  
  1147.         cmp exit_code, 08h    ; Variable not found?
  1148.         jz test_end
  1149.  
  1150.         dec si
  1151.         mov di, offset d_arg1    ; Set argument one.
  1152.         call copy_env        ; Copy the data out.
  1153.         mov s_arg1, cx        ; Save the size.
  1154.  
  1155. ;        Get argument two
  1156. arg_two:
  1157.         lodsb            ; Get a byte.
  1158.         cmp al, " "        ; Is it a space.
  1159.         jz arg_two
  1160.         cmp al, 09h        ; Is it a tab.
  1161.         jz arg_two
  1162.         cmp al, "'"        ; Is it a quote.
  1163.         jz quote2
  1164.         cmp al, '"'        ; Is it a quote.
  1165.         jz quote2
  1166.  
  1167.         cmp al, 0dh        ; Is it a carriage return.
  1168.         jnz test_arg2
  1169. no_argum:
  1170.         mov cs:[exit_code], 07h    ; Not a valid argument.
  1171.         jmp test_end        ; Exit.        
  1172.  
  1173. test_end:
  1174.         mov al, "E"        ; Error status.
  1175.         jmp log_end
  1176.  
  1177. quote2:
  1178.         mov di, offset d_arg2    ; Address of argument two.
  1179.         call get_quote        ; Get the quoted string.
  1180.  
  1181.         cmp exit_code, 06h    ; Unmatched quote?
  1182.         jz test_end
  1183.  
  1184.         mov s_arg2, cx        ; Save the size.
  1185.         jmp log_test
  1186.  
  1187. test_arg2:
  1188.         dec si
  1189.         call get_var0        ; Get the variable.
  1190.  
  1191.         cmp exit_code, 08h    ; Variable not found?
  1192.         jz test_end
  1193.  
  1194.         mov di, offset d_arg2    ; Set argument two.
  1195.         call copy_env        ; Copy the data out.
  1196.         mov s_arg2, cx        ; Save the size.
  1197.  
  1198. log_test:
  1199.         mov ax, offset d_arg1    ; Argument one.
  1200.         mov cx, s_arg1        ; Argument size.
  1201.         add ax, cx        ; At end of argument.
  1202.         mov si, ax        ; Set source.
  1203.  
  1204.         mov ax, offset d_arg2    ; Argument two.
  1205.         mov dx, s_arg2        ; Argument size.
  1206.         add ax, dx        ; At end of argument.
  1207.         mov di, ax        ; Set destination.
  1208.  
  1209. log_loop:
  1210.         cmp cx, 00h        ; Arg1 ran out of bytes.
  1211.         jz log_arg1
  1212.  
  1213.         cmp dx, 00h        ; Arg2 ran out of bytes.
  1214.         jz log_arg2
  1215.  
  1216.         dec si
  1217.         mov al, [si]        ; Get an arg1 byte.
  1218.         dec cx
  1219.  
  1220.         dec di
  1221.         mov bl, [di]        ; Get an arg2 byte.
  1222.         dec dx
  1223.  
  1224.         cmp al, bl        ; Are the equal?
  1225.         jz log_loop        ; Yes. Loop.
  1226.  
  1227.         jg log_great        ; Go to test for greater than.
  1228.  
  1229.         cmp l_oper, 0ffh    ; Less than operator?
  1230.         jz log_true        ; Yes. Then true.
  1231.  
  1232.         jmp log_false        ; No. Than false.
  1233.  
  1234. log_arg1:
  1235.         cmp dx, 00h        ; Arg2 ran out of bytes.
  1236.         jz log_equal
  1237.  
  1238.         cmp g_oper, 0ffh    ; Greater than operator?
  1239.         jz log_true        ; Yes. Then true.
  1240.         jmp log_false
  1241.  
  1242. log_arg2:
  1243.         cmp l_oper, 0ffh    ; Less than operator?
  1244.         jz log_true        ; Yes. Then true.
  1245.         jmp log_false
  1246.  
  1247. log_equal:
  1248.         cmp e_oper, 0ffh    ; Equal operator?
  1249.         jz log_true        ; Yes. Then true.
  1250.         jmp log_false
  1251.  
  1252. log_great:
  1253.         cmp g_oper, 0ffh    ; Greater than operator?
  1254.         jz log_true        ; Yes. Then true.
  1255. log_false:
  1256.         mov al, "F"        ; Test is false.
  1257.         jmp log_end
  1258.  
  1259. log_true:
  1260.         mov al, "T"        ; Test is true.
  1261.  
  1262. log_end:
  1263.         pop si
  1264.         push si
  1265.         dec si
  1266.         mov di, si        ; Move
  1267.         stosb            ;   in
  1268.         mov al, 0dh        ;     the
  1269.         stosb            ;        status.
  1270.  
  1271. log_exit:
  1272.         pop si
  1273.         pop di
  1274.         dec si
  1275.         jmp get_data        ; No. Jump out.
  1276.  
  1277.  
  1278. ;        Get the quoted string
  1279. get_quote:
  1280.         mov cx, 00h        ; Zero the counter.
  1281.         mov dl, al        ; Save the single quote.
  1282.  
  1283. get_quote1:
  1284.         lodsb            ; Get a byte.
  1285.         cmp al, " "        ; Is it a space.
  1286.         jz get_quote1
  1287.         cmp al, 09h        ; Is it a tab.
  1288.         jz get_quote1
  1289.         dec si
  1290.  
  1291. get_quote2:
  1292.         lodsb            ; Get a byte.
  1293.         cmp al, dl        ; Is it the end.
  1294.         jz get_quote4
  1295.  
  1296.         cmp al, 0dh        ; Is it the end of the command.
  1297.         jz get_quote3
  1298.  
  1299.         stosb            ; Save the byte.
  1300.         inc cx            ; Count the byte.
  1301.         jmp get_quote2
  1302.  
  1303. get_quote3:
  1304.         mov cs:[exit_code], 06h    ; Unmatched delimter.
  1305.  
  1306. get_quote4:
  1307.         ret
  1308.  
  1309.  
  1310. ;        Get variable data
  1311. get_var0:
  1312.         mov cx, 00h        ; Zero the counter.
  1313.         mov s_env, cx        ; Zero for use.
  1314.         mov di, offset n_env    ; Address of variable.
  1315.  
  1316. get_var1:
  1317.         lodsb            ; Get a byte.
  1318.         cmp al, " "        ; Is it the end of the variable?
  1319.         jz get_var2        ; Yes.  Jump out.
  1320.         cmp al, 09h        ; Is it the end of the variable?
  1321.         jz get_var2        ; Yes.  Jump out.
  1322.         cmp al, 0dh        ; Is it a carriage return.
  1323.         jz get_var2
  1324.  
  1325.         call uppercase        ; Convert to uppercase.
  1326.         stosb            ; Save the byte.
  1327.         inc cx            ; Count the byte.
  1328.         jmp get_var1
  1329.  
  1330. get_var2:
  1331.         cmp cx, 00h        ; Is there a variable name?
  1332.         jz get_var3
  1333.  
  1334.         mov s_env, cx        ; Variable name length.
  1335.         call loc_env        ; Get env variable base/offset.
  1336.         cmp f_env, 00h        ; Did we find the variable?
  1337.         jz get_var4
  1338.  
  1339. get_var3:
  1340.         mov cs:[exit_code], 08h    ; Variable not found.
  1341.  
  1342. get_var4:
  1343.         ret
  1344.  
  1345.  
  1346. percent:
  1347.         mov al, 1[si]
  1348.         cmp al, "+"        ; Is it a plus.
  1349.         jz off_drive
  1350.  
  1351.         cmp al, "-"        ; Is it a minus.
  1352.         jnz cwd
  1353.  
  1354. ;        Offset from a given drive.
  1355. off_drive:
  1356.         mov dh, al        ; Save the sign.
  1357.         mov dl, 2[si]
  1358.         cmp dl, "0"        ; Is
  1359.         jb off_drive0        ;   it
  1360.         cmp dl, "9"        ;     a
  1361.         jg off_drive0        ;       number.
  1362.         sub dl, 30h        ; Make it binary.
  1363.  
  1364.         mov ah, 19h        ; Get the disk drive.
  1365.         int 21h
  1366.  
  1367.         add al, "a"        ; Make it a letter.
  1368.         cmp dh, "+"
  1369.         jz off_drive1
  1370.         sub al, dl        ; Subtract from current drive.
  1371.         cmp al, "a"        ; If less then A
  1372.         jge off_drive2        ;   we have an error.
  1373. let_error:
  1374.         mov exit_code, 09h    ; Offset not valid.
  1375.         mov al, "%"        ; Put percent back.
  1376. off_drive0:
  1377.         jmp get_next
  1378.  
  1379. off_drive1:
  1380.         add al, dl        ; Add from current drive.
  1381.         cmp al, "z"        ; If greater then Z
  1382.         jg let_error        ;   we have an error.
  1383.  
  1384. off_drive2:
  1385.         stosb            ; Save the letter.
  1386.         inc si            ; Skip
  1387.         inc si            ;   over
  1388.         inc si            ;     %+n, or %-n.
  1389.  
  1390.         jmp get_data
  1391.  
  1392.  
  1393. ;        Handle %cwd.
  1394. cwd:
  1395.         push di
  1396.         push si
  1397.  
  1398.         mov di, si        ; Set destination.
  1399.         inc di
  1400.         mov si, offset l_cwd    ; Set Source.
  1401.         mov cx, s_cwd
  1402.         rep cmpsb        ; Is it %cwd.
  1403.         jz get_cwd        ; Yes.
  1404.  
  1405.         pop si
  1406.         push si
  1407.         mov di, si        ; Set destination.
  1408.         inc di
  1409.         mov si, offset u_cwd    ; Set source.
  1410.         mov cx, s_cwd
  1411.         rep cmpsb        ; Is it %CWD.
  1412.         jz get_cwd        ; Yes.
  1413.  
  1414.         pop si
  1415.         pop di
  1416.         jmp cfd            ; No. Jump out.
  1417.  
  1418. get_cwd:
  1419.         mov bx, di
  1420.         pop si
  1421.         pop di
  1422.         mov si, bx
  1423.  
  1424.         mov al, "\"        ; Put in the
  1425.         stosb            ;   root backslash.
  1426.         push si
  1427.         mov si, offset d_cwd    ; Place to put the directory name.
  1428.  
  1429.         mov ah, 47h        ; Get current directory.
  1430.         mov dl, 00h        ; Current disk drive.
  1431.         int 21h
  1432.  
  1433. cwd1:
  1434.         lodsb            ; Find the
  1435.         cmp al, 00h        ;   string
  1436.         jz cwd2            ;     terminator (zero).
  1437.  
  1438.         stosb            ; Store it.
  1439.         jmp cwd1
  1440.  
  1441. cwd2:
  1442.         pop si
  1443.         jmp get_data
  1444.  
  1445.  
  1446. ;        Handle %cfd.
  1447. cfd:
  1448.         push di
  1449.         push si
  1450.  
  1451.         mov di, si        ; Set destination.
  1452.         inc di
  1453.         mov si, offset l_cfd    ; Set Source.
  1454.         mov cx, s_cfd
  1455.         rep cmpsb        ; Is it %cfd.
  1456.         jz get_cfd        ; Yes.
  1457.  
  1458.         pop si
  1459.         push si
  1460.         mov di, si        ; Set destination.
  1461.         inc di
  1462.         mov si, offset u_cfd    ; Set source.
  1463.         mov cx, s_cfd
  1464.         rep cmpsb        ; Is it %CFD.
  1465.         jz get_cfd        ; Yes.
  1466.  
  1467.         pop si
  1468.         pop di
  1469.         jmp dosv        ; No. Jump out.
  1470.  
  1471. get_cfd:
  1472.         mov bx, di
  1473.         pop si
  1474.         pop di
  1475.         mov si, bx
  1476.  
  1477.         push si
  1478.         mov si, offset d_cwd    ; Place to put the directory name.
  1479.  
  1480.         mov ah, 47h        ; Get current directory.
  1481.         mov dl, 00h        ; Current disk drive.
  1482.         int 21h
  1483.  
  1484.         mov al, [si]        ; Is it the
  1485.         cmp al, 00h        ;   string
  1486.         jz cfd2            ;     terminator (zero).
  1487.  
  1488.         mov al, "\"        ; Put in the
  1489.         stosb            ;   root backslash.
  1490. cfd1:
  1491.         lodsb            ; Find the
  1492.         cmp al, 00h        ;   string
  1493.         jz cfd2            ;     terminator (zero).
  1494.  
  1495.         stosb            ; Store it.
  1496.         jmp cfd1
  1497.  
  1498. cfd2:
  1499.         mov al, "\"        ; Put in the
  1500.         stosb            ;   end backslash.
  1501.         pop si
  1502.         jmp get_data
  1503.  
  1504.  
  1505. ;        Handle %dosv.
  1506. dosv:
  1507.         push di
  1508.         push si
  1509.  
  1510.         mov di, si        ; Set destination.
  1511.         inc di
  1512.         mov si, offset l_dosv    ; Set Source.
  1513.         mov cx, s_dosv
  1514.         rep cmpsb        ; Is it %dosv.
  1515.         jz get_dosv        ; Yes.
  1516.  
  1517.         pop si
  1518.         push si
  1519.         mov di, si        ; Set destination.
  1520.         inc di
  1521.         mov si, offset u_dosv    ; Set source.
  1522.         mov cx, s_dosv
  1523.         rep cmpsb        ; Is it %DOSV.
  1524.         jz get_dosv        ; Yes.
  1525.  
  1526.         pop si
  1527.         pop di
  1528.         jmp dosm        ; No. Jump out.
  1529.  
  1530. get_dosv:
  1531.         mov bx, di
  1532.         pop si
  1533.         pop di
  1534.         mov si, bx
  1535.  
  1536.         mov ah, 30h        ; Get DOS version number.
  1537.         int 21h
  1538.  
  1539.         add al, "0"        ; Make it a number.
  1540.         stosb            ; Store it.
  1541.  
  1542.         jmp get_data
  1543.  
  1544.  
  1545. ;        Handle %dosm.
  1546. dosm:
  1547.         push di
  1548.         push si
  1549.  
  1550.         mov di, si        ; Set destination.
  1551.         inc di
  1552.         mov si, offset l_dosm    ; Set Source.
  1553.         mov cx, s_dosm
  1554.         rep cmpsb        ; Is it %dosm.
  1555.         jz get_dosm        ; Yes.
  1556.  
  1557.         pop si
  1558.         push si
  1559.         mov di, si        ; Set destination.
  1560.         inc di
  1561.         mov si, offset u_dosm    ; Set source.
  1562.         mov cx, s_dosm
  1563.         rep cmpsb        ; Is it %DOSM.
  1564.         jz get_dosm        ; Yes.
  1565.  
  1566.         pop si
  1567.         pop di
  1568.         jmp drive        ; No. Jump out.
  1569.  
  1570. get_dosm:
  1571.         mov bx, di
  1572.         pop si
  1573.         pop di
  1574.         mov si, bx
  1575.  
  1576.         mov ah, 30h        ; Get DOS version number.
  1577.         int 21h
  1578.  
  1579.         mov al, ah        ; Get minor version.
  1580.         cmp al, 0ah        ; Is it less then ten.
  1581.         jb dosm0        ; Yes. Jump out.
  1582.  
  1583.         call ascii        ; Do the minor version
  1584.         jmp dosm1
  1585. dosm0:
  1586.         add al, "0"        ; Make it a number.
  1587.         stosb            ; Store it.
  1588.  
  1589. dosm1:
  1590.         jmp get_data
  1591.  
  1592. ;        Handle %drive.
  1593. drive:
  1594.         push di
  1595.         push si
  1596.  
  1597.         mov di, si        ; Set destination.
  1598.         inc di
  1599.         mov si, offset l_drive    ; Set Source.
  1600.         mov cx, s_drive
  1601.         rep cmpsb        ; Is it %drive.
  1602.         jz get_drive        ; Yes.
  1603.  
  1604.         pop si
  1605.         push si
  1606.         mov di, si        ; Set destination.
  1607.         inc di
  1608.         mov si, offset u_drive    ; Set source.
  1609.         mov cx, s_drive
  1610.         rep cmpsb        ; Is it %DRIVE.
  1611.         jz get_drive        ; Yes.
  1612.  
  1613.         pop si
  1614.         pop di
  1615.         jmp time        ; No. Jump out.
  1616.  
  1617. get_drive:
  1618.         mov bx, di
  1619.         pop si
  1620.         pop di
  1621.         mov si, bx
  1622.  
  1623.         mov ah, 19h        ; Get the disk drive.
  1624.         int 21h
  1625.  
  1626.         add al, "a"        ; Make it a letter.
  1627.         stosb            ; Store it.
  1628.  
  1629.         jmp get_data
  1630.  
  1631.  
  1632. ;        Handle %time.
  1633. time:
  1634.         push di
  1635.         push si
  1636.  
  1637.         mov di, si        ; Set destination.
  1638.         inc di
  1639.         mov si, offset l_time    ; Set Source.
  1640.         mov cx, s_time
  1641.         rep cmpsb        ; Is it %time.
  1642.         jz get_time        ; Yes.
  1643.  
  1644.         pop si
  1645.         push si
  1646.         mov di, si        ; Set destination.
  1647.         inc di
  1648.         mov si, offset u_time    ; Set source.
  1649.         mov cx, s_time
  1650.         rep cmpsb        ; Is it %TIME.
  1651.         jz get_time        ; Yes.
  1652.  
  1653.         pop si
  1654.         pop di
  1655.         jmp date        ; No. Jump out.
  1656.  
  1657. get_time:
  1658.         mov bx, di
  1659.         pop si
  1660.         pop di
  1661.         mov si, bx
  1662.  
  1663.         mov ah, 2ch        ; Get the
  1664.         int 21h            ;   current time.
  1665.  
  1666.         mov bh, ":"        ; Separator.
  1667.         mov al, ch        ; Do the
  1668.         call ascii        ;   hours.
  1669.         mov al, bh        ; Do the
  1670.         stosb            ;   separator.
  1671.         mov al, cl        ; Do the
  1672.         call ascii        ;   minutes.
  1673.         mov al, bh        ; Do the
  1674.         stosb            ;   separator.
  1675.         mov al, dh        ; Do the
  1676.         call ascii        ;   seconds.
  1677.         
  1678.         jmp get_data
  1679.  
  1680.  
  1681. ;        Handle %date.
  1682. date:
  1683.         push di
  1684.         push si
  1685.  
  1686.         mov di, si        ; Set destination.
  1687.         inc di
  1688.         mov si, offset l_date    ; Set Source.
  1689.         mov cx, s_date
  1690.         rep cmpsb        ; Is it %date.
  1691.         jz get_date        ; Yes.
  1692.  
  1693.         pop si
  1694.         push si
  1695.         mov di, si        ; Set destination.
  1696.         inc di
  1697.         mov si, offset u_date    ; Set source.
  1698.         mov cx, s_date
  1699.         rep cmpsb        ; Is it %DATE.
  1700.         jz get_date        ; Yes.
  1701.  
  1702.         pop si
  1703.         pop di
  1704.         jmp character        ; No. Jump out.
  1705.  
  1706. get_date:
  1707.         mov bx, di
  1708.         pop si
  1709.         pop di
  1710.         mov si, bx
  1711.  
  1712.         lodsb            ; Get a byte.
  1713.         cmp al, "1"        ; Format one.
  1714.         jz date1        ; Yes. Jumpout.
  1715.         cmp al, "2"        ; Format two.
  1716.         jz date1        ; Yes. Jumpout.
  1717.         cmp al, "3"        ; Format three.
  1718.         jz date1        ; Yes. Jumpout.
  1719.         dec si
  1720.         mov al, z_date        ; Get the default.
  1721. date1:
  1722.         mov z_date, al        ; Save format.
  1723.         mov bh, "-"        ; Separator.
  1724.         
  1725.         mov ah, 2ah        ; Get the
  1726.         int 21h            ;   current date.
  1727.  
  1728.         cmp z_date, "3"
  1729.         jnz date2
  1730.         sub cx, 1900        ; Remove the century.
  1731.         mov al, cl        ; Do the
  1732.         call ascii        ;   year.
  1733.         mov al, bh        ; Do the
  1734.         stosb            ;   separator.
  1735. date2:
  1736.         cmp z_date, "1"
  1737.         jz date3
  1738.         mov al, dh        ; Do the
  1739.         call ascii        ;   month.
  1740.         mov al, bh        ; Do the
  1741.         stosb            ;   separator.
  1742. date3:
  1743.         mov al, dl        ; Do the
  1744.         call ascii        ;   Day.
  1745.  
  1746.         cmp z_date, "3"
  1747.         jz date9
  1748.         mov al, bh        ; Do the
  1749.         stosb            ;   separator.
  1750.  
  1751.         cmp z_date, "2"
  1752.         jz date4
  1753.  
  1754.         mov al, dh        ; Do the
  1755.         call ascii        ;   month.
  1756.         mov al, bh        ; Do the
  1757.         stosb            ;   separator.
  1758. date4:
  1759.         mov al, dh        ; Do the
  1760.         sub cx, 1900        ; Remove the century.
  1761.         mov al, cl        ; Do the
  1762.         call ascii        ;   year.
  1763.  
  1764. date9:        
  1765.         jmp get_data
  1766.  
  1767.  
  1768. ;        convert a binary number to two digit decimal.
  1769. ascii:
  1770.         mov bl, 0ah        ; Divide
  1771.         cbw            ;   by
  1772.         div bl            ;     ten.
  1773.         add al, "0"        ; Make it a number.
  1774.         stosb            ; Store tens.
  1775.         add ah, "0"        ; Make it a number.
  1776.         mov al, ah
  1777.         stosb            ; Store ones.
  1778.         ret
  1779.  
  1780.  
  1781. ;        Handle %chr.
  1782. character:
  1783.         push di
  1784.         push si
  1785.  
  1786.         mov di, si        ; Set destination.
  1787.         inc di
  1788.         mov si, offset l_chr    ; Set Source.
  1789.         mov cx, s_chr
  1790.         rep cmpsb        ; Is it %chr.
  1791.         jz get_character    ; Yes.
  1792.  
  1793.         pop si
  1794.         push si
  1795.         mov di, si        ; Set destination.
  1796.         inc di
  1797.         mov si, offset u_chr    ; Set Source.
  1798.         mov cx, s_chr
  1799.         rep cmpsb        ; Is it %CHR.
  1800.         jz get_character    ; Yes.
  1801.  
  1802.         pop si
  1803.         pop di
  1804.         jmp element        ; No. Jump out.
  1805.  
  1806. get_character:
  1807.         mov bx, di
  1808.         pop si
  1809.         pop di
  1810.         mov si, bx
  1811.  
  1812.         mov ax, 00h
  1813.         mov s_env, ax        ; Zero for use.
  1814.  
  1815.         lodsb            ; Get the delimiter.
  1816.         mov dl, al        ; Save it.
  1817.         push di
  1818.  
  1819.         call p_numb        ; Read number.
  1820.         mov n_chr, cx        ; Save element number.
  1821.  
  1822.         pop di
  1823.         cmp cx, 00h        ; Is it going to be a null.
  1824.         jz character1        ; No. Error.
  1825.  
  1826.         cmp cx, 0ffh        ; Is it valid?
  1827.         jbe character2        ; Yes. Jump out.
  1828.  
  1829. character1:
  1830.         mov cs:[exit_code], 09h    ; Range error.
  1831.         jmp nor_term        ; Exit.
  1832.  
  1833. character2:
  1834.         mov al, cl        ; Character is okay.
  1835.         stosb            ; Save the byte.
  1836.         jmp get_data
  1837.  
  1838.  
  1839. ;        Handle %elem.
  1840. element:
  1841.         push di
  1842.         push si
  1843.  
  1844.         mov di, si        ; Set destination.
  1845.         inc di
  1846.         mov si, offset l_elem    ; Set Source.
  1847.         mov cx, s_elem
  1848.         rep cmpsb        ; Is it %elem.
  1849.         jz get_element        ; Yes.
  1850.  
  1851.         pop si
  1852.         push si
  1853.         mov di, si        ; Set destination.
  1854.         inc di
  1855.         mov si, offset u_elem    ; Set Source.
  1856.         mov cx, s_elem
  1857.         rep cmpsb        ; Is it %ELEM.
  1858.         jz get_element        ; Yes.
  1859.  
  1860.         pop si
  1861.         pop di
  1862.         jmp substr        ; No. Jump out.
  1863.  
  1864. get_element:
  1865.         mov bx, di
  1866.         pop si
  1867.         pop di
  1868.         mov si, bx
  1869.  
  1870.         mov ax, 00h
  1871.         mov e_elem, ax        ; Zero
  1872.         mov c_elem, al        ;   values
  1873.         mov s_env, ax        ;     for use.
  1874.  
  1875.         lodsb            ; Get the delimiter.
  1876.         mov dl, al        ; Save it.
  1877.         push di
  1878.  
  1879.         call p_numb        ; Read number.
  1880.         mov e_elem, cx        ; Save element number.
  1881.  
  1882. element1:
  1883.         lodsb            ; Get a byte.
  1884.         cmp al, 0dh        ; Is it a return?
  1885.         jz element2        ; Yes Jump out.
  1886.  
  1887.         cmp al, dl        ; Is it a delimiter?
  1888.         jz element3        ; Yes. Jump out.
  1889.         mov c_elem, al        ; Save element delimiter.
  1890.         jmp element1
  1891.  
  1892. element2:
  1893.         pop di
  1894.         dec si
  1895.         mov cs:[exit_code], 06h    ; Unmatched delimter.
  1896.         jmp nor_term        ; Exit.
  1897.  
  1898. element3:
  1899.         mov di, offset n_env    ; Store variable name here.
  1900.         call p_var        ; Read a string.
  1901.         mov s_env, cx        ; Save the size.
  1902.         pop di
  1903.  
  1904.         call loc_env        ; Get variable offset
  1905.         cmp f_env, 00h        ; Did we find the variable?
  1906.         jz element9
  1907.  
  1908.         dec si
  1909.         mov cs:[exit_code], 08h    ; Variable not found.
  1910.         jmp nor_term        ; Exit.        
  1911.  
  1912. element9:
  1913.         mov dx, e_elem        ; Element number.
  1914.         mov cx, 00h
  1915.  
  1916.         mov ax, o_env        ; Environment offset.
  1917.         mov bx, b_env        ; Environment base.
  1918.         push si
  1919.         push ds
  1920.         mov si, ax        ; Set for the
  1921.         mov ds, bx        ;   environment.
  1922.  
  1923.         cmp cx, dx        ; Is it the number 0.
  1924.         jz element11        ; Yes. Get it.
  1925.  
  1926. element10:
  1927.         lodsb            ; Get a byte.
  1928.         cmp al, 00h        ; At end of variable string?
  1929.         jz element12        ; Yes. Jump out.
  1930.  
  1931.         cmp al, cs:[c_elem]    ; Is it a delimiter?
  1932.         jnz element10        ; No. Loop.
  1933.  
  1934.         inc cx
  1935.         cmp cx, dx        ; Is it the right one.
  1936.         jnz element10        ; No. Loop.
  1937.  
  1938. element11:
  1939.         lodsb            ; Get a byte.
  1940.         cmp al, 00h        ; At end of variable string?
  1941.         jz element13        ; Yes. Jump out.
  1942.  
  1943.         cmp al, cs:[c_elem]    ; Is it a delimiter?
  1944.         jz element13        ; No. Loop.
  1945.  
  1946.         stosb            ; Save the byte.
  1947.         jmp element11
  1948.  
  1949. element12:
  1950.         pop ds
  1951.         pop si
  1952.         mov cs:[exit_code], 09h    ; Offset not valid.
  1953.         jmp nor_term        ; Exit.        
  1954.  
  1955. element13:
  1956.         pop ds
  1957.         pop si
  1958.  
  1959.         jmp get_data
  1960.  
  1961.  
  1962. ;        Handle %mid.
  1963. substr:
  1964.         push di
  1965.         push si
  1966.  
  1967.         mov di, si        ; Set destination.
  1968.         inc di
  1969.         mov si, offset l_mid    ; Set Source.
  1970.         mov cx, s_mid
  1971.         rep cmpsb        ; Is it %mid.
  1972.         jz get_substr        ; Yes.
  1973.  
  1974.         pop si
  1975.         push si
  1976.         mov di, si        ; Set destination.
  1977.         inc di
  1978.         mov si, offset u_mid    ; Set Source.
  1979.         mov cx, s_mid
  1980.         rep cmpsb        ; Is it %MID.
  1981.         jz get_substr        ; Yes.
  1982.  
  1983.         pop si
  1984.         pop di
  1985.         jmp locate        ; No. Jump out.
  1986.  
  1987. get_substr:
  1988.         mov bx, di
  1989.         pop si
  1990.         pop di
  1991.         mov si, bx
  1992.  
  1993.         mov ax, 00h
  1994.         mov y_mid, ax        ; Zero
  1995.         mov z_mid, ax        ;   values
  1996.         mov s_env, ax        ;     for use.
  1997.  
  1998.         lodsb            ; Get the delimiter.
  1999.         mov dl, al        ; Save it.
  2000.         push di
  2001.  
  2002.         mov di, offset n_env    ; Store variable name here.
  2003.         call p_var        ; Read a string.
  2004.         mov s_env, cx        ; Variable length.
  2005.  
  2006.         call p_numb        ; Read number.
  2007.         mov y_mid, cx        ; Save start postion.
  2008.  
  2009.         call p_numb        ; Read number.
  2010.         mov z_mid, cx        ; Save length to get.
  2011.         pop di
  2012.  
  2013.         call loc_env        ; Get variable offset
  2014.         cmp f_env, 00h        ; Did we find the variable?
  2015.         jz substr9
  2016.  
  2017.         mov cs:[exit_code], 08h    ; Variable not found.
  2018.         jmp nor_term        ; Exit.        
  2019.  
  2020. substr9:
  2021.         mov cx, z_mid        ; Length of substr.
  2022.         cmp cx, 00h        ; If not zero.
  2023.         jnz substr10
  2024.  
  2025.         mov cx, 0ffh        ; Make it large.
  2026. substr10:
  2027.         mov dx, y_mid        ; Starting position.
  2028.         cmp dx, 00h        ; If not zero.
  2029.         jnz substr11
  2030.  
  2031.         add dx, 01h        ; Make it one.
  2032. substr11:
  2033.         mov ax, o_env        ; Get env. variable offset.
  2034.         mov bx, ax        ; Add starting
  2035.         add bx, dx        ;   position.
  2036.  
  2037.         mov dx, b_env        ; Get env. base address.
  2038.         push si    
  2039.         push ds
  2040.         mov si, ax
  2041.         mov ds, dx
  2042.  
  2043. substr12:
  2044.         lodsb            ; Get a byte.
  2045.         cmp al, 00h        ; At end of variable data?
  2046.         jz substr13
  2047.  
  2048.         cmp si, bx        ; At starting position?
  2049.         jz substr14
  2050.         jmp substr12
  2051.  
  2052. substr13:
  2053.         pop ds
  2054.         pop si
  2055.         mov cs:[exit_code], 09h    ; Offset not valid.
  2056.         jmp nor_term        ; Exit.        
  2057.  
  2058. substr14:
  2059.         dec si
  2060.  
  2061. substr15:
  2062.         lodsb            ; Get a byte.
  2063.         cmp al, 00h        ; At end of variable data?
  2064.         jz substr16
  2065.  
  2066.         cmp cx, 00h        ; At end of length?
  2067.         jz substr16
  2068.  
  2069.         stosb            ; Move the byte.
  2070.         dec cx            ; One less byte to check.
  2071.         jmp substr15
  2072.  
  2073. substr16:
  2074.         pop ds
  2075.         pop si
  2076.  
  2077.         jmp get_data
  2078.  
  2079.  
  2080. ;        Handle %loc.
  2081. locate:
  2082.         push di
  2083.         push si
  2084.  
  2085.         mov di, si        ; Set destination.
  2086.         inc di
  2087.         mov si, offset l_loc    ; Set Source.
  2088.         mov cx, s_loc
  2089.         rep cmpsb        ; Is it %loc.
  2090.         jz get_locate        ; Yes.
  2091.  
  2092.         pop si
  2093.         push si
  2094.         mov di, si        ; Set destination.
  2095.         inc di
  2096.         mov si, offset u_loc    ; Set Source.
  2097.         mov cx, s_loc
  2098.         rep cmpsb        ; Is it %LOC.
  2099.         jz get_locate        ; Yes.
  2100.  
  2101.         pop si
  2102.         pop di
  2103.         jmp length0        ; No. Jump out.
  2104.  
  2105. get_locate:
  2106.         mov bx, di
  2107.         pop si
  2108.         pop di
  2109.         mov si, bx
  2110.  
  2111.         mov ax, 00h
  2112.         mov e_loc, ax        ; Zero
  2113.         mov s_env, ax        ;   values
  2114.         mov w_mid, ax        ;     for use.
  2115.  
  2116.         lodsb            ; Get the delimiter.
  2117.         mov dl, al        ; Save it.
  2118.         push di
  2119.  
  2120.         call p_numb        ; Read number.
  2121.         mov e_loc, cx        ; Save starting position.
  2122.  
  2123.         mov di, offset n_env    ; Store variable name here.
  2124.         call p_var        ; Read a string.
  2125.         mov s_env, cx        ; Variable length.
  2126.  
  2127.         mov di, offset x_mid    ; Store search string.
  2128.         call p_str        ; Read a string.
  2129.         mov w_mid, cx        ; Variable length.
  2130.         pop di
  2131.  
  2132.         call loc_env        ; Get variable offset
  2133.         cmp f_env, 00h        ; Did we find the variable?
  2134.         jz locate9
  2135.  
  2136.         mov cs:[exit_code], 08h    ; Variable not found.
  2137.         jmp nor_term        ; Exit.        
  2138.  
  2139. locate9:
  2140.         mov dx, e_loc        ; Starting position.
  2141.         cmp dx, 00h        ; If not zero.
  2142.         jnz locate10
  2143.  
  2144.         add dx, 01h        ; Make it one.
  2145. locate10:
  2146.         mov ax, o_env        ; Get env. variable offset.
  2147.         mov bx, ax        ; Add starting
  2148.         add bx, dx        ;   position.
  2149.  
  2150.         mov dx, b_env        ; Get env. base address.
  2151.         push si    
  2152.         push ds
  2153.         mov si, ax
  2154.         mov ds, dx
  2155.  
  2156. locate11:
  2157.         lodsb            ; Get a byte.
  2158.         cmp al, 00h        ; At end of variable data?
  2159.         jz locate12
  2160.  
  2161.         cmp si, bx        ; At starting position?
  2162.         jz locate13
  2163.         jmp locate11
  2164.  
  2165. locate12:
  2166.         pop ds
  2167.         pop si
  2168.         mov ax, 00h        ; Set for not found.
  2169.         jmp locate17
  2170.  
  2171. locate13:
  2172.         dec si
  2173.         push di
  2174.  
  2175. locate14:
  2176.         mov al, [si]        ; Get a test byte.
  2177.         cmp al, 00h        ; At end of variable data?
  2178.         jz locate15
  2179.  
  2180.         push si
  2181.  
  2182.         mov di, offset cs:[x_mid] ; Set destination.
  2183.         mov cx, cs:[w_mid]    ; Set Length.
  2184.         rep cmpsb        ; Is it the string.
  2185.         jz locate16        ; Yes. Jump out.
  2186.  
  2187.         pop si            ; Get offset back.
  2188.         inc si            ; Move on a byte.
  2189.         jmp locate14
  2190.  
  2191. locate15:
  2192.         pop di
  2193.         jmp locate12
  2194.  
  2195.  
  2196. locate16:
  2197.         mov ax, si        ; Save the offset
  2198.         pop si
  2199.         pop di
  2200.  
  2201.         pop ds
  2202.         pop si
  2203.  
  2204.         mov bx, o_env        ; Subtract env data
  2205.         sub ax, bx        ;   start from current location.
  2206.         mov bx, w_mid        ; Subtract
  2207.         sub ax, bx        ;   search length.
  2208.         inc ax
  2209.  
  2210. locate17:
  2211.         call dec_str
  2212.  
  2213.         jmp get_data
  2214.  
  2215.  
  2216. ;        Handle %len.
  2217. length0:
  2218.         push di
  2219.         push si
  2220.  
  2221.         mov di, si        ; Set destination.
  2222.         inc di
  2223.         mov si, offset l_len    ; Set Source.
  2224.         mov cx, s_len
  2225.         rep cmpsb        ; Is it %len.
  2226.         jz get_length        ; Yes.
  2227.  
  2228.         pop si
  2229.         push si
  2230.         mov di, si        ; Set destination.
  2231.         inc di
  2232.         mov si, offset u_len    ; Set Source.
  2233.         mov cx, s_len
  2234.         rep cmpsb        ; Is it %LEN.
  2235.         jz get_length        ; Yes.
  2236.  
  2237.         pop si
  2238.         pop di
  2239.         jmp sum_var        ; No. Jump out.
  2240.  
  2241. get_length:
  2242.         mov bx, di
  2243.         pop si
  2244.         pop di
  2245.         mov si, bx
  2246.  
  2247.         mov ax, 00h
  2248.         mov s_env, ax        ; Zero for use.
  2249.  
  2250.         lodsb            ; Get the delimiter.
  2251.         mov dl, al        ; Save it.
  2252.         push di
  2253.  
  2254.         mov di, offset n_env    ; Store variable name here.
  2255.         call p_var        ; Read a string.
  2256.         mov s_env, cx        ; Variable length.
  2257.         pop di
  2258.  
  2259.         call loc_env        ; Get variable offset
  2260.         cmp f_env, 00h        ; Did we find the variable?
  2261.         jz length9
  2262.  
  2263.         mov cs:[exit_code], 08h    ; Variable not found.
  2264.         jmp nor_term        ; Exit.        
  2265.  
  2266. length9:
  2267.         mov ax, o_env        ; Get env. variable offset.
  2268.         mov dx, b_env        ; Get env. base address.
  2269.         mov cx, 00h
  2270.  
  2271.         push si    
  2272.         push ds
  2273.         mov si, ax
  2274.         mov ds, dx
  2275.  
  2276. length10:
  2277.         lodsb            ; Get a byte.
  2278.         cmp al, 00h        ; At end of variable data?
  2279.         jz length11
  2280.  
  2281.         inc cx            ; Count the bytes.
  2282.         jmp length10
  2283.  
  2284. length11:
  2285.         pop ds
  2286.         pop si
  2287.  
  2288.         mov ax, cx        ; Save length.
  2289.         call dec_str
  2290.  
  2291.         jmp get_data
  2292.  
  2293.  
  2294. ;        Handle %sum.
  2295. sum_var:
  2296.         push di
  2297.         push si
  2298.  
  2299.         mov di, si        ; Set destination.
  2300.         inc di
  2301.         mov si, offset l_sum    ; Set Source.
  2302.         mov cx, s_sum
  2303.         rep cmpsb        ; Is it %sum.
  2304.         jz get_sum_var        ; Yes.
  2305.  
  2306.         pop si
  2307.         push si
  2308.         mov di, si        ; Set destination.
  2309.         inc di
  2310.         mov si, offset u_sum    ; Set Source.
  2311.         mov cx, s_sum
  2312.         rep cmpsb        ; Is it %SUM.
  2313.         jz get_sum_var        ; Yes.
  2314.  
  2315.         pop si
  2316.         pop di
  2317.         jmp get_next        ; No. Jump out.
  2318.  
  2319. get_sum_var:
  2320.         mov bx, di
  2321.         pop si
  2322.         pop di
  2323.         mov si, bx
  2324.  
  2325.         mov ax, 00h
  2326.         mov s_env, ax        ; Zero for use.
  2327.  
  2328.         lodsb            ; Get the delimiter.
  2329.         mov dl, al        ; Save it.
  2330.         push di
  2331.  
  2332.         mov di, offset n_env    ; Store variable name here.
  2333.         call p_var        ; Read a string.
  2334.         mov s_env, cx        ; Variable length.
  2335.  
  2336.         mov nmb_tst, 0ffh    ; Set to test sign.
  2337.         call p_numb        ; Read number.
  2338.         mov v_sum, cx        ; Save sum number.
  2339.         mov nmb_tst, 00h    ; Remove test for sign.
  2340.         pop di
  2341.  
  2342.         call loc_env        ; Get variable offset
  2343.         cmp f_env, 00h        ; Did we find the variable?
  2344.         jz sum_var9
  2345.  
  2346.         mov cs:[exit_code], 08h    ; Variable not found.
  2347.         jmp nor_term        ; Exit.        
  2348.  
  2349. sum_var9:
  2350.         mov ax, o_env        ; Get env. variable offset.
  2351.         mov dx, b_env        ; Get env. base address.
  2352.         mov cx, 00h
  2353.         mov f_sum, "+"        ; Set for add.
  2354.  
  2355.         push si    
  2356.         push ds
  2357.         mov si, ax
  2358.         mov ds, dx
  2359.  
  2360. sum_var10:
  2361.         lodsb            ; Get a byte.
  2362.         cmp al, " "        ; Leading space.
  2363.         jz sum_var10        ; Then remove it.
  2364.  
  2365.         cmp al, 09h        ; Leading tab.
  2366.         jz sum_var10        ; Then remove it.
  2367.  
  2368.         cmp al, "+"        ; Is it an add.
  2369.         jz sum_var12
  2370.  
  2371.         cmp al, "-"        ; Is it an minus.
  2372.         jnz sum_var11
  2373.         mov cs:[f_sum], "-"
  2374.         jmp sum_var12
  2375.  
  2376. sum_var11:
  2377.         dec si
  2378. sum_var12:
  2379.         lodsb            ; Get a byte.
  2380.         cmp al, "9"        ; Is
  2381.         jg sum_var14        ;   it
  2382.         cmp al, "0"        ;     numeric?
  2383.         jb sum_var14        ; No. Then error.
  2384.  
  2385.         mov ah, 00h
  2386.         sub al, 30h        ; Make it binary.
  2387.         mov bx, ax        ; Save next digit.
  2388.         mov ax, cx        ; Get the number.
  2389.         push dx
  2390.         push bx
  2391.         mov bx, 0ah        ; Multiply 
  2392.         mul bx            ;   by ten.
  2393.         pop bx
  2394.         pop dx
  2395.         add ax, bx        ; Add next digit.
  2396.         mov cx, ax        ; Save number.
  2397.         jmp sum_var12
  2398.  
  2399. sum_var13:
  2400.         lodsb            ; Get a byte.
  2401. sum_var14:
  2402.         cmp al, 00h        ; At end of variable data?
  2403.         jz sum_var15
  2404.  
  2405.         cmp al, " "        ; Leading space.
  2406.         jz sum_var13        ; Then remove it.
  2407.  
  2408.         cmp al, 09h        ; Leading tab.
  2409.         jz sum_var13        ; Then remove it.
  2410.  
  2411.         pop di
  2412.         dec si
  2413.         mov cs:[exit_code], 07h    ; Argument not a number.
  2414.         jmp nor_term        ; Exit.
  2415.  
  2416. sum_var15:        
  2417.         pop ds
  2418.         pop si
  2419.  
  2420.         mov ax, cx        ; Value of the variable.
  2421.         mov cx, v_sum        ; Value to add.
  2422.  
  2423.         cmp nmb_sgn, "+"    ; Is the number positive?
  2424.         jz sum_var16
  2425.  
  2426.         cmp f_sum, "+"        ; Is the variable positive?
  2427.         jz sum_var17
  2428.  
  2429.         push ax
  2430.         mov al, "-"        ; Write out
  2431.         stosb            ;   the sign.
  2432.         pop ax
  2433.         jmp sum_var21
  2434.  
  2435. sum_var16:
  2436.         cmp f_sum, "+"        ; Is the variable positive?
  2437.         jz sum_var21
  2438.  
  2439. sum_var17:
  2440.         cmp ax, cx        ; Is the number gt the variable?
  2441.         jge sum_var20
  2442.  
  2443.         mov dx, cx        ; Then
  2444.         mov cx, ax        ;   switch
  2445.         mov ax, dx        ;     them arround.
  2446.  
  2447.         cmp nmb_sgn, "+"    ; Is the number positive?
  2448.         jz sum_var19
  2449. sum_var18:
  2450.         push ax
  2451.         mov al, "-"        ; Write out
  2452.         stosb            ;   the sign.
  2453.         pop ax                
  2454.  
  2455. sum_var19:
  2456.         sub ax, cx        ; Subtract the difference.
  2457.         jmp sum_var22
  2458.  
  2459. sum_var20:
  2460.         cmp f_sum, "+"        ; Is the variable positive?
  2461.         jz sum_var19        
  2462.  
  2463.         cmp ax, cx        ; No sign if equal.
  2464.         jz sum_var19
  2465.         jmp sum_var18
  2466.  
  2467. sum_var21:
  2468.         add ax, cx        ; Add the number to variable.
  2469.  
  2470. sum_var22:
  2471.         call dec_str        ; Convert to decimal string.
  2472.  
  2473.         jmp get_data
  2474.  
  2475.  
  2476. ;        parse a number from the command line
  2477. p_numb:
  2478.         lodsb            ; Get a byte.
  2479.         cmp al, " "        ; Leading space.
  2480.         jz p_numb        ; Then remove it.
  2481.  
  2482.         cmp al, 09h        ; Leading tab.
  2483.         jz p_numb        ; Then remove it.
  2484.  
  2485.         mov cx, 00h
  2486.         cmp nmb_tst, 00h    ; Do we test for sign.
  2487.         jz p_numb1
  2488.  
  2489.         mov nmb_sgn, "+"    ; Set initial sign.
  2490.         cmp al, "+"        ; Is it an add.
  2491.         jz p_numb2
  2492.  
  2493.         cmp al, "-"        ; Is it an minus.
  2494.         jnz p_numb1
  2495.         mov nmb_sgn, "-"    ; Save the sign.
  2496.         jmp p_numb2
  2497.  
  2498. p_numb1:
  2499.         dec si
  2500.  
  2501. ;        The maximum element is 255.
  2502. p_numb2:
  2503.         lodsb            ; Get a byte.
  2504.         cmp al, "9"        ; Is
  2505.         jg p_numb4        ;   it
  2506.         cmp al, "0"        ;     numeric?
  2507.         jb p_numb4        ; No. Then error.
  2508.  
  2509.         mov ah, 00h
  2510.         sub al, 30h        ; Make it binary.
  2511.         mov bx, ax        ; Save next digit.
  2512.         mov ax, cx        ; Get the number.
  2513.         push dx
  2514.         push bx
  2515.         mov bx, 0ah        ; Multiply 
  2516.         mul bx            ;   by ten.
  2517.         pop bx
  2518.         pop dx
  2519.         add ax, bx        ; Add next digit.
  2520.         mov cx, ax        ; Save number.
  2521.         jmp p_numb2
  2522.  
  2523. p_numb3:
  2524.         lodsb            ; Get a byte.
  2525. p_numb4:
  2526.         cmp al, 0dh        ; Is it the end?
  2527.         jz p_numb5        ; Yes Jump out.
  2528.  
  2529.         cmp al, dl        ; Digits over?.
  2530.         jz p_numb6        ; Yes Jump out.
  2531.  
  2532.         cmp al, " "        ; Leading space.
  2533.         jz p_numb3        ; Then remove it.
  2534.  
  2535.         cmp al, 09h        ; Leading tab.
  2536.         jz p_numb3        ; Then remove it.
  2537.  
  2538.         pop di
  2539.         dec si
  2540.         mov cs:[exit_code], 07h    ; Argument not a number.
  2541.         jmp nor_term        ; Exit.
  2542.  
  2543. p_numb5:
  2544.         pop di
  2545.         dec si
  2546.         mov cs:[exit_code], 06h    ; Unmatched delimter.
  2547.         jmp nor_term        ; Exit.
  2548.  
  2549. p_numb6:
  2550.         ret
  2551.  
  2552.  
  2553. ;        parse the variable from the command line
  2554. p_str:
  2555.         mov cx, 00h
  2556.  
  2557. p_str1:
  2558.         lodsb            ; Get a byte.
  2559.         cmp al, 0dh        ; Is it the end?
  2560.         jz p_numb5        ; Yes Jump out.
  2561.  
  2562.         cmp al, dl        ; Is it a delimiter?
  2563.         jz p_str3        ; Yes. Jump out.
  2564.  
  2565. p_str2:
  2566.         stosb            ; Save it.
  2567.         inc cx            ; Increment the count.
  2568.         jmp p_str1
  2569.  
  2570. p_str3:
  2571.         ret
  2572.  
  2573.  
  2574. ;        parse a string from the command line
  2575. ;        and convert lower to upper
  2576. p_var:
  2577.         lodsb            ; Get a byte.
  2578.         cmp al, " "        ; Leading space.
  2579.         jz p_var        ; Then remove it.
  2580.  
  2581.         cmp al, 09h        ; Leading tab.
  2582.         jz p_var        ; Then remove it.
  2583.  
  2584.         dec si
  2585.         mov cx, 00h
  2586.  
  2587. p_var1:
  2588.         lodsb            ; Get a byte.
  2589.         cmp al, 0dh        ; Is it the end?
  2590.         jz p_numb5        ; Yes Jump out.
  2591.  
  2592.         cmp al, dl        ; Is it a delimiter?
  2593.         jz p_var2        ; Yes. Jump out.
  2594.  
  2595.         cmp al, " "        ; Leading space.
  2596.         jz p_var1        ; Then remove it.
  2597.  
  2598.         cmp al, 09h        ; Leading tab.
  2599.         jz p_var1        ; Then remove it.
  2600.  
  2601.         call uppercase        ; Convert to uppercase.
  2602.         stosb            ; Save it.
  2603.         inc cx            ; Increment the count.
  2604.         jmp p_var1
  2605.  
  2606. p_var2:
  2607.         ret
  2608.  
  2609.  
  2610. ;        End of data now finish it.
  2611. data_end:
  2612.         mov al, 00h        ; Save
  2613.         stosb            ;   two
  2614.         stosb            ;     nulls.
  2615.         mov ax, di        ; Get the offset.
  2616.         mov bx, offset d_env_var ; The beginng of the variable.
  2617.         sub ax, bx        ; Get the data length.
  2618.         mov s_data, ax        ; And save it.
  2619.  
  2620.         cmp v_rep, 0ffh        ; Are we going to replace.
  2621.         jz get_psp        ; Yes. Jump.
  2622.         cmp v_rce, 00h        ; Are we going to do root.
  2623.         jz get_psp        ; No.  Jump over.
  2624.         jmp set_root
  2625.  
  2626. get_psp:
  2627.         push ds            ; Save the segment base.
  2628.  
  2629. ;        PSP of program.
  2630.         mov si, 16h
  2631.         mov ax, [si]
  2632.  
  2633. ;        Parent PSP Segment of program.
  2634.         mov ds, ax        ; Set the data segment.
  2635.         mov si, 16h        ; Parent PSP Segment.
  2636.         mov ax, [si]
  2637.  
  2638. ;        Parent PSP Segment of command.com.
  2639.         mov ds, ax        ; Set the data segment.
  2640.         mov si, 16h        ; Parent PSP Segment.
  2641.         mov ax, [si]
  2642.         mov cs:[cpsp], ax
  2643.  
  2644. ;        Check if the Environment Address is usable.
  2645.         mov si, 2ch        ; Environment space
  2646.         mov bx, [si]        ;   of command.com.
  2647.         cmp bx, 00h        ; If it's zero we
  2648.         jz zero_add        ;   do a long search.
  2649.  
  2650.         sub bx, 01h        ; We will have to back
  2651.         mov ax, bx        ;   up to env. definition.
  2652.  
  2653. zero_add:
  2654. ;        Segment where the environment space is.
  2655.         mov ds, ax
  2656.         mov si, 00h
  2657.  
  2658. get4d:
  2659. ;        Look for 4dh on segment boundary.
  2660.         mov al, [si]
  2661.         cmp al, 4dh
  2662.         jz got4d
  2663.  
  2664. inc_seg:
  2665.         mov ax, si        ; Increment
  2666.         add ax, 10h        ;   to the next
  2667.         mov si, ax        ;      segment boundary.
  2668.  
  2669. ;        Start of Stop the program from searching for ever.
  2670.         cmp ax, 0f000h        ; Have we gone way passed 64k?
  2671.         jb get4d        ; No. Continue.
  2672.  
  2673.         pop ds            ; Restore the data segment.
  2674.         push ds            ; Save the segment base.
  2675.         mov dx, offset get4d_err
  2676.         mov ah, 09h        ; display the error.
  2677.         int 21h
  2678.         mov exit_code, 00h    ; No exit.
  2679.         jmp nor_term        ; Exit.
  2680. ;        End of Stop the program from searching for ever.
  2681.  
  2682. got4d:
  2683.         mov ax, 1[si]        ; Get the psp.
  2684.         cmp cs:[cpsp], ax    ; Is it the same as cpsp?
  2685.         jnz inc_seg        ; No.  Jump out.
  2686.  
  2687.         mov ah, 00h
  2688.         mov al, 3[si]        ; Get the number of segments.
  2689.         mov bx, 10h
  2690.         mul bx            ; Get the number of bytes.
  2691.         mov cs:[env_siz], ax    ; Save it.
  2692.  
  2693.         mov ax, si        ; Increment
  2694.         add ax, 10h        ;   to the environment
  2695.         mov si, ax        ;      segment boundary.
  2696.         mov cs:[env_off], ax    ; Save it.
  2697.  
  2698. ;        Just a double check for environment space.
  2699. ;        Check for PATH= or PROMPT= or COMPEC= or SETENV=.
  2700.         mov ax, ds        ; Get the data segment
  2701.         mov es, ax        ; and put it in extra segment.
  2702.         mov di, si        ; This is our destination.
  2703.  
  2704.         pop ds            ; Restore the data segment.
  2705.         mov si, offset d_path    ; Check
  2706.         mov cx, s_path        ;   for
  2707.         rep cmpsb        ;     PATH=.
  2708.         jz got_env
  2709.  
  2710.         mov di, env_off        ; Restore the destination.
  2711.         mov si, offset d_prompt    ; Check
  2712.         mov cx, s_prompt    ;   for
  2713.         rep cmpsb        ;     PROMPT=.
  2714.         jz got_env
  2715.  
  2716.         mov di, env_off        ; Restore the destination.
  2717.         mov si, offset d_comspec ;Check
  2718.         mov cx, s_comspec    ;    for
  2719.         rep cmpsb        ;      COMSPEC=.
  2720.         jz got_env
  2721.  
  2722.         mov di, env_off        ; Restore the destination.
  2723.         mov si, offset d_setenv    ; Check
  2724.         mov cx, s_setenv    ;   for
  2725.         rep cmpsb        ;     SETENV=.
  2726.         jz got_env
  2727.  
  2728.         mov di, env_off        ; Restore the destination.
  2729.         mov si, offset d_config    ; Check
  2730.         mov cx, s_config    ;   for
  2731.         rep cmpsb        ;     CONFIG=.
  2732.         jz got_env
  2733.  
  2734.         push ds            ; Save the data segment.
  2735.         mov ax, es        ; Get the
  2736.         mov ds, ax        ;   data segment
  2737.         mov si, cs:[env_off]    ;     and source
  2738.         jmp get4d        ;       to scan some more.
  2739.  
  2740. got_env:
  2741.         push ds            ; Save the data segment.
  2742.         mov ax, es        ; Get the
  2743.         mov ds, ax        ;   data segment
  2744.         mov si, cs:[env_off]    ;     and source.
  2745.  
  2746.         mov di, offset cs:[d_env_var]    ; First character
  2747.         mov bl, cs:[di]        ;   of environment variable.
  2748.         jmp zero1
  2749. ;        Scan through environment for the end,
  2750. ;        we need two null bytes.
  2751. loop:
  2752.         lodsb            ; Get a byte.
  2753.         cmp al, 00h        ; Is it null?
  2754.         jz zero1        ; Yes. Got first null.
  2755.         jmp loop        ; Keep looking.
  2756.  
  2757. ;        Is the variable there?
  2758. zero1:
  2759.         lodsb            ; Get a byte.
  2760.         cmp al, 00h        ; Is it zero?
  2761.         jz write_near        ; Yes.  Jump out.
  2762.         cmp al, bl        ; Is it the env. variable?
  2763.         jnz loop        ; No.  Jump out.
  2764.  
  2765.         dec si            ; We are N+1.
  2766.         mov ax, ds        ; Get the data segment
  2767.         mov es, ax        ; and put it in extra segment.
  2768.         mov di, si        ; This is our destination.
  2769.  
  2770.         mov dx, si        ; Save the address of env. var.
  2771.         pop ds            ; Restore the data segment.
  2772.         mov si, offset d_env_var ; Set the source.
  2773.         mov cx, s_env_var    ; Length of variable.
  2774.         rep cmpsb        ; Does it exist?
  2775.         jz update
  2776.  
  2777.         push ds            ; Save the data segment.
  2778.         mov ax, es        ; Get the extra segment.
  2779.         mov ds, ax        ; and put it in data segment.
  2780.         mov si, di        ; Setup the source.
  2781.         jmp loop
  2782.  
  2783. write_near:
  2784.         jmp write
  2785. subst_near:
  2786.         jmp substitute
  2787. change_near:
  2788.         jmp change
  2789.  
  2790.  
  2791. ;        The environment variable is there.
  2792. ;        Now update the environment variable.
  2793. update:
  2794.         cmp cs:[v_rep], 0ffh    ; Do we replace?
  2795.         jz subst_near        ; Yes. Go there.
  2796.  
  2797.         cmp cs:[v_chgup], 0ffh    ; Do we upper case string?
  2798.         jz change_near        ; Yes. Go there.
  2799.  
  2800.         cmp cs:[v_chglo], 0ffh    ; Do we lower case string?
  2801.         jz change_near        ; Yes. Go there.
  2802.  
  2803. update0:
  2804.         push ds            ; Save the data segment.
  2805.         mov ax, es        ; Get the extra segment.
  2806.         mov ds, ax        ; and put it in data segment.
  2807.         mov di, dx        ; This is our destination.
  2808.         mov si, di        ; Setup the source.
  2809.         
  2810. update1:
  2811.         lodsb            ; Skip
  2812.         cmp al, 00h        ;   over
  2813.         jnz update1        ;     the variable.
  2814.  
  2815.         lodsb            ; Look ahead to see
  2816.         dec si            ;   if the next byte
  2817.         cmp al, 00h        ;     is zero if not
  2818.         jz update3        ;       compress the data.
  2819.  
  2820. update2:
  2821.         lodsb            ; Compress
  2822.         stosb            ;   the data
  2823.         cmp al, 00h        ;     for a
  2824.         jnz update2        ;       variable.
  2825.  
  2826.         lodsb            ; Get a byte.
  2827.         dec si
  2828.         cmp al, 00h        ; Is it zero?
  2829.         jnz update2        ; No.  Get next.
  2830.  
  2831. update3:
  2832.         mov al, cs:[exit_code]
  2833.         cmp al, 05h
  2834.         jg update4
  2835.         mov cs:[exit_code], 05h    ; Environment variable updated.
  2836. update4:
  2837.         mov cx, cs:[s_data]    ; Length of data.
  2838.         mov dx, cs:[s_env_var]    ; Length of name.
  2839.         sub cx, dx
  2840.         sub cx, 02h        ; Minus 2 zeroes.
  2841.         cmp cx, 00h        ; Is it just the name.
  2842.         jnz write1        ; No. Jump out.
  2843.  
  2844.         mov cx, si        ; End of old environment.
  2845.         mov dx, di        ; Current position.
  2846.         sub cx, dx
  2847.         mov al, 00h        ; Zero
  2848.         rep stosb        ;  the rest.
  2849.         mov cs:[exit_code], 02h    ; Environment variable erased.
  2850.         jmp nor_term
  2851.  
  2852. ;        The environment variable isn't there.
  2853. ;        Now move the data into place.
  2854. write:
  2855.         mov ax, ds        ; Get the data segment
  2856.         mov es, ax        ; and put it in extra segment.
  2857.         dec si            ; We are N+1.
  2858.         mov di, si        ; This is our destination.
  2859.  
  2860. write1:
  2861.         mov cx, cs:[s_data]    ; Environment variable & data.
  2862.         dec cx            ; No
  2863.         dec cx            ;   nulls.
  2864.         mov ax, cs:[s_env_var]    ; Environment variable size.
  2865.         cmp ax, cx        ; Same size.
  2866.         jne write2        ; No. Jump out.
  2867.         mov cs:[exit_code], 08h    ; Environment variable not found.
  2868.         jmp nor_term
  2869.  
  2870. write2:
  2871.         pop ds            ; Restore the data segment.
  2872.         mov si, offset d_env_var ; Set the source.
  2873.         mov cx, s_data        ; Set the length.
  2874. write3:
  2875.         mov ah, es:[di]        ; Get destination byte.
  2876. write4:
  2877.         cmp ah, 00h        ; Is it a zero?
  2878.         jnz not_zero        ; No.  Jump out.
  2879.         lodsb            ; Get byte.
  2880.         stosb            ; Save byte.
  2881.         loop write3        ; Loop.
  2882.  
  2883. ;        Exit the program.
  2884. nor_term:
  2885.         mov al, cs:[exit_code]    ; Set termination code.
  2886.         mov ah, 4ch        ; Termination.
  2887.         int 21h
  2888.  
  2889. not_zero:
  2890.         mov ax, di        ; Get the current offset.
  2891.         mov bx, env_off        ; Get environment start.
  2892.         sub ax, bx        ; Subtract the start of env.
  2893.         mov bx, env_siz        ; Get environment size.
  2894.         cmp ax, bx        ; Greater the environment size.
  2895.         jge reset        ; Yes.  Jump.
  2896.         mov ah, 00h        ; Make it zero.
  2897.         mov al, exit_code    ; Get exit code.
  2898.         cmp al, 05h        ; If update then do not
  2899.         jmp write4        ;   reduce the error code.
  2900. ;        jge write4        ;   reduce the error code.
  2901. ;        mov exit_code, 04h    ; Environment space over written.
  2902. ;        jmp write4        ;   and redo.
  2903.  
  2904. reset:
  2905.         dec di
  2906.         dec di
  2907.         mov al, 00h        ; Put zero back.
  2908.         stosb
  2909.         stosb
  2910.         mov exit_code, 10h    ; Set code for out of env.,
  2911.         jmp nor_term        ;   and terminate.
  2912.  
  2913. ;        Replace old text with new text.
  2914. substitute:
  2915.         push dx
  2916.         push ds
  2917.         push es
  2918.         push si
  2919.         push di
  2920.  
  2921.         mov ax, es        ; Switch
  2922.         mov bx, ds        ;   the
  2923.         mov es, bx        ;     segments
  2924.         mov ds, ax        ;       around.
  2925.  
  2926.         mov ax, di        ; Switch
  2927.         mov di, si        ;   the
  2928.         mov si, ax        ;     registrars.
  2929.  
  2930.         mov bx, offset d_arg1    ; Get first byte
  2931.         mov dl, cs:[bx]        ;   of old data.
  2932. subst1:
  2933.         lodsb            ; Get byte.
  2934.         cmp al, 00h        ; End of variable space.
  2935.         jz subst5        ; Yes. Jump out.
  2936.  
  2937.         cmp al, dl        ; First byte of data?
  2938.         jz subst3        ; Yes. Jump out
  2939. subst2:
  2940.         stosb            ; Save byte.
  2941.         jmp subst1
  2942.  
  2943. ;        Test for old text.
  2944. subst3:
  2945.         push ds
  2946.         push es
  2947.         push di
  2948.         push si
  2949.  
  2950.         mov ax, es        ; Switch
  2951.         mov bx, ds        ;   the
  2952.         mov es, bx        ;     segments
  2953.         mov ds, ax        ;       around.
  2954.  
  2955.         mov di, si
  2956.         dec di            ; Data N+1.
  2957.         mov si, offset d_arg1    ; Old data value.
  2958.         mov cx, cs:[s_arg1]    ; Old data size.
  2959.         rep cmpsb
  2960.         jz subst4
  2961.  
  2962.         mov al, dl        ; Get byte back.
  2963.         pop si
  2964.         pop di
  2965.         pop es
  2966.         pop ds
  2967.         jmp subst2
  2968.  
  2969. ;        Put in new text.
  2970. subst4:
  2971.         pop si
  2972.         pop di
  2973.         mov ax, ds
  2974.         mov es, ax
  2975.  
  2976.         mov bx, si
  2977.         dec si            ; Data N+1.
  2978.         push si
  2979.  
  2980.         mov si, offset d_arg2    ; New data value.
  2981.         mov cx, s_arg2        ; New data size.
  2982.         rep movsb
  2983.  
  2984.         pop si
  2985.         mov cx, si
  2986.         mov ax, s_arg1        ; Add size of
  2987.         add cx, ax        ;   new value.
  2988.         mov si, cx        ; Advance the size.
  2989.  
  2990.         pop es
  2991.         pop ds
  2992.         jmp subst1
  2993.  
  2994. subst5:
  2995.         stosb            ; Save two
  2996.         stosb            ;   nulls.
  2997.         pop di
  2998.         pop si
  2999.         pop es
  3000.         pop ds
  3001.  
  3002.         mov v_rep, 00h        ; Turn off replace.
  3003.         push si
  3004.         push di
  3005.  
  3006.         mov si, offset d_env_var
  3007.         mov cx, 00h
  3008. subst6:
  3009.         lodsb            ; Get
  3010.         inc cx            ;   the
  3011.         cmp al, 00h        ;     size.
  3012.         jnz subst6
  3013.  
  3014.         inc cx
  3015.         mov s_data, cx        ; Save the size.
  3016.  
  3017.         pop di
  3018.         pop si
  3019.         pop dx
  3020.         jmp update0
  3021.  
  3022. ;        Replace old text with new text, for case.
  3023. change:
  3024.         mov ax, es        ; Switch
  3025.         mov ds, ax        ;   the
  3026.         mov si, di        ;     registers.
  3027.  
  3028. change1:
  3029.         lodsb            ; Get a byte.
  3030.         cmp al, 00h        ; Is it null?
  3031.         jz change9        ; Yes. End of variable.
  3032.  
  3033.         cmp cs:[v_chgup], 0ffh    ; Do we upper case string?
  3034.         jnz change2
  3035.         call uppercase        ; Convert to uppercase.
  3036.         jmp change3
  3037.  
  3038. change2:
  3039.         cmp cs:[v_chglo], 0ffh    ; Do we lower case string?
  3040.         jnz change3
  3041.         call lowercase        ; Convert to lowercase.
  3042.  
  3043. change3:
  3044.         stosb            ; Replace it.
  3045.         jmp change1        ; Next byte.
  3046.  
  3047. change9:
  3048.         mov cs:[exit_code], 05h    ; Environment variable updated.
  3049.         jmp nor_term
  3050.  
  3051.  
  3052. ;        Root environment.
  3053. set_root:
  3054.         mov si, offset set    ; Move in the 'set='
  3055.         mov di, offset d_rce    ;   into the data area.
  3056.         inc di            ; Leave room for size.
  3057.         mov cx, 04h
  3058.         rep movsb        ; Move string.
  3059.  
  3060.         mov si, offset d_env_var ; Environment data.
  3061.         mov cx, s_data
  3062.         dec cx            ; Ignore the
  3063.         dec cx            ;   two nulls.
  3064.         rep movsb        ; Move string.
  3065.  
  3066.         mov al, 0dh        ; Put in the CR to terminate.
  3067.         stosb
  3068.         mov ax, s_data        ; Set the size and
  3069.         inc al            ;   add the
  3070.         inc al            ;     size for 'set='.
  3071.         mov byte ptr d_rce, al    ; Save the count.
  3072.  
  3073.         mov bx, offset lastloc+15 ; bx := program size
  3074.         mov cx, 04h        ;   in paragraphs.
  3075.         shr bx, cl
  3076.         mov ax, 4a00h        ; Deallocate unused memory.
  3077.         int 21h
  3078.  
  3079.         mov si, offset d_rce    ; Point at command.
  3080.         int 02eh        ; Execute the DOS command.
  3081.  
  3082.         mov ax, cs
  3083.         mov ss, ax
  3084.         mov ds, ax
  3085.         mov es, ax
  3086.         mov cs:[exit_code], 01h    ; Set code for environment
  3087.         jmp nor_term        ;   root set and terminate.
  3088.  
  3089. ;        convert a binary number to decimal string.
  3090. dec_str:
  3091.         mov    byte ptr dec_zfl, 0ffh    ; leading zero flag
  3092.         mov    bx, 10000
  3093.         call    dec_dig            ; get the 10000's digit
  3094.         mov    bx, 1000
  3095.         call    dec_dig            ; get the 1000's digit
  3096.         mov    bx, 100
  3097.         call    dec_dig            ; get the 100's digit
  3098.         mov    bx, 10
  3099.         call    dec_dig            ; get the 10's digit
  3100.         add    al, '0'            ; get the 1's digit
  3101.         jmp    dec_mov
  3102.  
  3103. dec_dig:
  3104.         mov    dx, 00h            ; clear remainder
  3105.         div    bx            ; divide ax by digit value
  3106.         add    al, '0'            ; convert to ascii digit
  3107.  
  3108.         cmp    byte ptr dec_zfl, 0ffh    ; suppress zero
  3109.         jne    dec_mov            ; no.  jump out
  3110.  
  3111.         cmp    al, '0'            ; if it a zero
  3112.         je    dec_nxt            ; yes.  jump out
  3113.         mov    byte ptr dec_zfl, 0h    ; set print zero
  3114.  
  3115. dec_mov:
  3116.         stosb                ; store the digit
  3117. dec_nxt:
  3118.         mov    ax, dx            ; setup for next digit
  3119.         ret
  3120.  
  3121.  
  3122. ;        Convert lowercase to uppercase.
  3123. uppercase:
  3124.         cmp al, "z"        ; Is
  3125.         jg not_lower1        ;   it
  3126.         cmp al, "a"        ;     lower
  3127.         jb not_lower1        ;       case?
  3128.         sub al, 20h        ; Make it upper case.
  3129. not_lower1:
  3130.         ret
  3131.  
  3132.  
  3133. ;        Convert uppercase to lowercase.
  3134. lowercase:
  3135.         cmp al, "Z"        ; Is
  3136.         jg not_upper1        ;   it
  3137.         cmp al, "A"        ;     upper
  3138.         jb not_upper1        ;       case?
  3139.         add al, 20h        ; Make it lower case.
  3140. not_upper1:
  3141.         ret
  3142.  
  3143.  
  3144. ;        copy environment variable data out.
  3145. copy_env:
  3146.         push ds
  3147.         push es
  3148.         push di
  3149.         push si
  3150.  
  3151.         mov ax, o_env        ; Get env. variable offset.
  3152.         mov si, ax
  3153.         mov ax, b_env        ; Get env. bas address.
  3154.  
  3155.         mov ds, ax        ; Set source.
  3156.         mov cx, 00h        ; Zero counter.
  3157.  
  3158. copy_env1:
  3159.         lodsb            ; Get a byte.
  3160.         cmp al, 00h        ; At end of variable data?
  3161.         jz copy_env2
  3162.  
  3163.         inc cx            ; Count the bytes.
  3164.         stosb            ; Save the byte.
  3165.         jmp copy_env1
  3166.  
  3167. copy_env2:
  3168.         pop si
  3169.         pop di
  3170.         pop es
  3171.         pop ds
  3172.         ret
  3173.  
  3174.  
  3175. ;    subroutine to find a variable in the local environment
  3176. loc_env:
  3177.         push ax
  3178.         push bx
  3179.         push cx
  3180.         push dx
  3181.         push si
  3182.         push di
  3183.         push es
  3184.         push ds
  3185.  
  3186.         mov al, 0ffh
  3187.         mov f_env, al        ; Initialize flag.
  3188.         mov ax, b_env        ; Get environment base address.
  3189.         cmp ax, 00h        ; Is it zero?
  3190.         jnz loc_env1        ; Yes Jump out.
  3191.  
  3192.         mov si, 2ch        ; Environment offset.
  3193.         mov ax, [si]        ; Get the address.
  3194.         mov b_env, ax        ; Save it.
  3195.  
  3196. loc_env1:
  3197.         mov bx, 00h        ; Offset of source.
  3198.         mov dx, offset n_env    ; Offset of destination.
  3199.  
  3200.         mov ax, b_env        ; Get environment base.
  3201.         mov ds, ax        ; Set environment base.
  3202. loc_env2:
  3203.         mov si, bx        ; Set source offset.
  3204.         mov di, dx        ; Point at the variable.
  3205.         mov cx, cs:[s_env]    ; Length of variable.
  3206.         rep cmpsb        ; Is it here.
  3207.         jz loc_env5
  3208.  
  3209.         mov si, bx        ; Backup over this variable.
  3210. loc_env3:
  3211.         lodsb            ; Search
  3212.         cmp al, 00h        ;  for end
  3213.         jnz loc_env3        ;    of varible.
  3214.  
  3215.         mov al, [si]        ; Are we at
  3216.         cmp al, 00h        ;   the end of
  3217.         jz loc_env9        ;     the environment?
  3218.  
  3219.         mov bx, si        ; Set for new variable.
  3220.         jmp loc_env2
  3221.  
  3222. loc_env5:
  3223.         mov al, [si]        ; We have the variable.
  3224.         cmp al, "="        ; Is it only a first part?
  3225.         jnz loc_env3        ; No. Look again.
  3226.  
  3227.         pop ds
  3228.         inc si            ; Skip equal sign.
  3229.         mov o_env, si        ; Set offset.
  3230.         mov al, 00h        ; Search success.
  3231.         mov f_env, al        ; Set it.
  3232.         push ds
  3233.  
  3234. loc_env9:
  3235.         pop ds
  3236.         pop es
  3237.         pop di
  3238.         pop si
  3239.         pop dx
  3240.         pop cx
  3241.         pop bx
  3242.         pop ax
  3243.         ret
  3244.  
  3245.  
  3246. ;        Generate a character if % is there.
  3247. make_char:
  3248.         cmp al, "%"        ; Is it percent.
  3249.         jnz make_char3
  3250.  
  3251.         lodsb            ; Get the delimiter.
  3252.         cmp al, "/"        ; Is it a /.
  3253.         jnz make_char2
  3254.  
  3255.         mov dl, al        ; Save it.
  3256.         push di
  3257.  
  3258.         call p_numb        ; Read number.
  3259.         mov n_chr, cx        ; Save element number.
  3260.  
  3261.         pop di
  3262.         cmp cx, 00h        ; Is it going to be a null.
  3263.         jz make_char2        ; No. Error.
  3264.  
  3265.         cmp cx, 0ffh        ; Is it valid?
  3266.         jg make_char3        ; Yes. Jump out.
  3267.  
  3268.         mov al, cl        ; Character is okay.
  3269.         jmp make_char3
  3270. make_char2:
  3271.         dec si
  3272.         mov al, "%"        ; Put the percent back.
  3273. make_char3:
  3274.         ret
  3275.  
  3276.  
  3277.         db    128 dup (?)    ; Stack.
  3278. stack        label    byte
  3279.  
  3280. lastloc        label    byte        ; End of program.
  3281. code ends
  3282.      end start
  3283. 
  3284.